mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-22 08:56:34 +03:00
Build libpq from Python
This commit is contained in:
parent
73f6a0cd95
commit
c875197432
|
@ -85,60 +85,6 @@ init:
|
|||
install:
|
||||
- "%PYEXE% C:\\appveyor.py install"
|
||||
|
||||
# Setup directories for building PostgreSQL librarires
|
||||
- ECHO *******************************************************************
|
||||
- ECHO Preparing for building PostgreSQL libraries
|
||||
- ECHO *******************************************************************
|
||||
- SET PGTOP=%BASE_DIR%\postgresql
|
||||
- IF NOT EXIST %PGTOP%\include MKDIR %PGTOP%\include
|
||||
- IF NOT EXIST %PGTOP%\lib MKDIR %PGTOP%\lib
|
||||
- IF NOT EXIST %PGTOP%\bin MKDIR %PGTOP%\bin
|
||||
|
||||
# Download PostgreSQL source
|
||||
- CD C:\Others
|
||||
- IF NOT EXIST postgres-REL_%POSTGRES_VERSION%.zip (
|
||||
curl -fsSL -o postgres-REL_%POSTGRES_VERSION%.zip https://github.com/postgres/postgres/archive/REL_%POSTGRES_VERSION%.zip
|
||||
)
|
||||
|
||||
# Setup build config file (config.pl)
|
||||
# Hack the Mkvcbuild.pm file so we build the lib version of libpq
|
||||
# Build libpgport, libpgcommon, libpq
|
||||
# Install includes
|
||||
# Copy over built libraries
|
||||
# Prepare local include directory for building from
|
||||
# Build pg_config in place
|
||||
# Note patch for OpenSSL 1.1 configuration. See:
|
||||
# https://www.postgresql-archive.org/Compile-psql-9-6-with-SSL-Version-1-1-0-td6054118.html
|
||||
# NOTE: Cannot set and use the same variable inside an IF
|
||||
- SET PGBUILD=%BUILD_DIR%\postgres-REL_%POSTGRES_VERSION%
|
||||
- IF NOT EXIST %PGTOP%\lib\libpq.lib (
|
||||
CD %BUILD_DIR% &&
|
||||
7z x C:\Others\postgres-REL_%POSTGRES_VERSION%.zip &&
|
||||
CD postgres-REL_%POSTGRES_VERSION% &&
|
||||
patch -p1 < %APPVEYOR_BUILD_FOLDER%\scripts\win_openssl_11.patch &&
|
||||
CD src\tools\msvc &&
|
||||
ECHO $config-^>{ldap} = 0; > config.pl &&
|
||||
ECHO $config-^>{openssl} = "%OPENSSLTOP:\=\\%"; >> config.pl &&
|
||||
ECHO.>> config.pl &&
|
||||
ECHO 1;>> config.pl &&
|
||||
perl -pi.bak -e "s/'libpq', 'dll'/'libpq', 'lib'/g" Mkvcbuild.pm &&
|
||||
build libpgport &&
|
||||
build libpgcommon &&
|
||||
build libpq &&
|
||||
ECHO "" > %PGBUILD%\src\backend\parser\gram.h &&
|
||||
perl -pi.bak -e "s/qw\(Install\)/qw\(Install CopyIncludeFiles\)/g" Install.pm &&
|
||||
perl -MInstall=CopyIncludeFiles -e"chdir('../../..'); CopyIncludeFiles('%PGTOP%')" &&
|
||||
COPY %PGBUILD%\Release\libpgport\libpgport.lib %PGTOP%\lib &&
|
||||
COPY %PGBUILD%\Release\libpgcommon\libpgcommon.lib %PGTOP%\lib &&
|
||||
COPY %PGBUILD%\Release\libpq\libpq.lib %PGTOP%\lib &&
|
||||
XCOPY /Y /S %PGBUILD%\src\include\port\win32\* %PGBUILD%\src\include &&
|
||||
XCOPY /Y /S %PGBUILD%\src\include\port\win32_msvc\* %PGBUILD%\src\include &&
|
||||
CD %PGBUILD%\src\bin\pg_config &&
|
||||
cl pg_config.c /MT /nologo /I%PGBUILD%\src\include /link /LIBPATH:%PGTOP%\lib libpgcommon.lib libpgport.lib advapi32.lib /NODEFAULTLIB:libcmt.lib /OUT:%PGTOP%\bin\pg_config.exe &&
|
||||
CD %BASE_DIR% &&
|
||||
RMDIR /S /Q %PGBUILD%
|
||||
)
|
||||
|
||||
build: off
|
||||
|
||||
#before_build:
|
||||
|
|
|
@ -95,15 +95,13 @@ def setup_env():
|
|||
|
||||
def python_info():
|
||||
logger.info("Python Information")
|
||||
out = call_command([py_exe(), '--version'], stderr=sp.STDOUT)
|
||||
out = out_command([py_exe(), '--version'], stderr=sp.STDOUT)
|
||||
logger.info("%s", out)
|
||||
|
||||
cmdline = [
|
||||
py_exe(),
|
||||
'-c',
|
||||
"import sys; print('64bit: %s' % (sys.maxsize > 2**32))",
|
||||
]
|
||||
out = call_command(cmdline)
|
||||
out = out_command(
|
||||
[py_exe(), '-c']
|
||||
+ ["import sys; print('64bit: %s' % (sys.maxsize > 2**32))"]
|
||||
)
|
||||
logger.info("%s", out)
|
||||
|
||||
|
||||
|
@ -128,12 +126,19 @@ def step_init():
|
|||
|
||||
|
||||
def step_install():
|
||||
build_openssl()
|
||||
# TODO: enable again
|
||||
# build_openssl()
|
||||
build_libpq()
|
||||
|
||||
|
||||
def build_openssl():
|
||||
# Setup directories for building OpenSSL libraries
|
||||
top = os.path.join(base_dir(), 'openssl')
|
||||
if os.path.exists(os.path.join(top, 'lib', 'libssl.lib')):
|
||||
return
|
||||
|
||||
logger.info("Building OpenSSL")
|
||||
|
||||
# Setup directories for building OpenSSL libraries
|
||||
ensure_dir(os.path.join(top, 'include', 'openssl'))
|
||||
ensure_dir(os.path.join(top, 'lib'))
|
||||
|
||||
|
@ -156,27 +161,16 @@ def build_openssl():
|
|||
f"https://github.com/openssl/openssl/archive/{zipname}", zipfile
|
||||
)
|
||||
|
||||
if os.path.exists(os.path.join(top, 'lib', 'libssl.lib')):
|
||||
return
|
||||
|
||||
with ZipFile(zipfile) as z:
|
||||
z.extractall(path=build_dir())
|
||||
|
||||
os.chdir(os.path.join(build_dir(), f"openssl-OpenSSL_{ver}"))
|
||||
cmdline = [
|
||||
'perl',
|
||||
'Configure',
|
||||
target,
|
||||
'no-asm',
|
||||
'no-shared',
|
||||
'no-zlib',
|
||||
f'--prefix={top}',
|
||||
f'--openssldir={top}',
|
||||
]
|
||||
call_command(cmdline, output=False)
|
||||
run_command(
|
||||
['perl', 'Configure', target, 'no-asm']
|
||||
+ ['no-shared', 'no-zlib', f'--prefix={top}', f'--openssldir={top}']
|
||||
)
|
||||
|
||||
cmdline = "nmake build_libs install_dev".split()
|
||||
call_command(cmdline, output=False)
|
||||
run_command("nmake build_libs install_dev".split())
|
||||
|
||||
assert os.path.exists(os.path.join(top, 'lib', 'libssl.lib'))
|
||||
|
||||
|
@ -184,8 +178,115 @@ def build_openssl():
|
|||
shutil.rmtree(os.path.join(build_dir(), f"openssl-OpenSSL_{ver}"))
|
||||
|
||||
|
||||
def build_libpq():
|
||||
top = os.path.join(base_dir(), 'postgresql')
|
||||
if os.path.exists(os.path.join(top, 'lib', 'libpq.lib')):
|
||||
return
|
||||
|
||||
logger.info("Building libpq")
|
||||
|
||||
# Setup directories for building PostgreSQL librarires
|
||||
ensure_dir(os.path.join(top, 'include'))
|
||||
ensure_dir(os.path.join(top, 'lib'))
|
||||
ensure_dir(os.path.join(top, 'bin'))
|
||||
|
||||
ver = os.environ['POSTGRES_VERSION']
|
||||
|
||||
# Download PostgreSQL source
|
||||
zipname = f'postgres-REL_{ver}.zip'
|
||||
zipfile = os.path.join(r'C:\Others', zipname)
|
||||
if not os.path.exists(zipfile):
|
||||
download(
|
||||
f"https://github.com/postgres/postgres/archive/REL_{ver}.zip",
|
||||
zipfile,
|
||||
)
|
||||
|
||||
with ZipFile(zipfile) as z:
|
||||
z.extractall(path=build_dir())
|
||||
|
||||
pgbuild = os.path.join(build_dir(), f"postgres-REL_{ver}")
|
||||
os.chdir(pgbuild)
|
||||
|
||||
# Patch for OpenSSL 1.1 configuration. See:
|
||||
# https://www.postgresql-archive.org/Compile-psql-9-6-with-SSL-Version-1-1-0-td6054118.html
|
||||
assert os.path.exists("src/include/pg_config.h.win32")
|
||||
with open("src/include/pg_config.h.win32", 'a') as f:
|
||||
print(
|
||||
"""
|
||||
#define HAVE_ASN1_STRING_GET0_DATA 1
|
||||
#define HAVE_BIO_GET_DATA 1
|
||||
#define HAVE_BIO_METH_NEW 1
|
||||
#define HAVE_OPENSSL_INIT_SSL 1
|
||||
""",
|
||||
file=f,
|
||||
)
|
||||
|
||||
# Setup build config file (config.pl)
|
||||
os.chdir("src/tools/msvc")
|
||||
with open("config.pl", 'w') as f:
|
||||
print(
|
||||
"""\
|
||||
$config->{ldap} = 0;
|
||||
$config->{openssl} = "%s";
|
||||
|
||||
1;
|
||||
"""
|
||||
% os.path.join(base_dir(), 'openssl').replace('\\', '\\\\'),
|
||||
file=f,
|
||||
)
|
||||
|
||||
# Hack the Mkvcbuild.pm file so we build the lib version of libpq
|
||||
file_replace('Mkvcbuild.pm', "'libpq', 'dll'", "'libpq', 'lib'")
|
||||
|
||||
# Build libpgport, libpgcommon, libpq
|
||||
run_command([which("build"), "libpgport"])
|
||||
run_command([which("build"), "libpgcommon"])
|
||||
run_command([which("build"), "libpq"])
|
||||
|
||||
# Install includes
|
||||
with open(os.path.join(pgbuild, "src/backend/parser/gram.h"), "w") as f:
|
||||
print("", file=f)
|
||||
|
||||
# Copy over built libraries
|
||||
file_replace("Install.pm", "qw(Install)", "qw(Install CopyIncludeFiles)")
|
||||
run_command(
|
||||
["perl", "-MInstall=CopyIncludeFiles", "-e"]
|
||||
+ [f"chdir('../../..'); CopyIncludeFiles('{top}')"]
|
||||
)
|
||||
|
||||
for lib in ('libpgport', 'libpgcommon', 'libpq'):
|
||||
shutil.copy(
|
||||
os.path.join(pgbuild, f'Release/{lib}/{lib}.lib'),
|
||||
os.path.join(top, 'lib'),
|
||||
)
|
||||
|
||||
# Prepare local include directory for building from
|
||||
for dir in ('win32', 'win32_msvc'):
|
||||
merge_dir(
|
||||
os.path.join(pgbuild, f"src/include/port/{dir}"),
|
||||
os.path.join(pgbuild, "src/include"),
|
||||
)
|
||||
|
||||
# Build pg_config in place
|
||||
os.chdir(os.path.join(pgbuild, 'src/bin/pg_config'))
|
||||
run_command(
|
||||
['cl', 'pg_config.c', '/MT', '/nologo', fr'/I{pgbuild}\src\include']
|
||||
+ ['/link', fr'/LIBPATH:{top}\lib']
|
||||
+ ['libpgcommon.lib', 'libpgport.lib', 'advapi32.lib']
|
||||
+ ['/NODEFAULTLIB:libcmt.lib']
|
||||
+ [fr'/OUT:{top}\bin\pg_config.exe']
|
||||
)
|
||||
|
||||
assert os.path.exists(os.path.join(top, 'lib', 'libpq.lib'))
|
||||
assert os.path.exists(os.path.join(top, 'bin', 'pg_config.exe'))
|
||||
|
||||
os.chdir(base_dir())
|
||||
shutil.rmtree(os.path.join(pgbuild))
|
||||
|
||||
|
||||
def download(url, fn):
|
||||
"""Download a file locally"""
|
||||
logger.info("downloading %s", url)
|
||||
with open(fn, 'wb') as fo, urlopen(url) as fi:
|
||||
while 1:
|
||||
data = fi.read(8192)
|
||||
|
@ -193,6 +294,37 @@ def download(url, fn):
|
|||
break
|
||||
fo.write(data)
|
||||
|
||||
logger.info("file downloaded: %s", fn)
|
||||
|
||||
|
||||
def file_replace(fn, s1, s2):
|
||||
"""
|
||||
Replace all the occurrences of the string s1 into s2 in the file fn.
|
||||
"""
|
||||
assert os.path.exists(fn)
|
||||
with open(fn, 'r+') as f:
|
||||
data = f.read()
|
||||
f.seek(0)
|
||||
f.write(data.replace(s1, s2))
|
||||
f.truncate()
|
||||
|
||||
|
||||
def merge_dir(src, tgt):
|
||||
"""
|
||||
Merge the content of the directory src into the directory tgt
|
||||
|
||||
Reproduce the semantic of "XCOPY /Y /S src/* tgt"
|
||||
"""
|
||||
for dp, _dns, fns in os.walk(src):
|
||||
logger.debug("dirpath %s", dp)
|
||||
if not fns:
|
||||
continue
|
||||
assert dp.startswith(src)
|
||||
subdir = dp[len(src) :].lstrip(os.sep)
|
||||
tgtdir = ensure_dir(os.path.join(tgt, subdir))
|
||||
for fn in fns:
|
||||
shutil.copy(os.path.join(dp, fn), tgtdir)
|
||||
|
||||
|
||||
def bat_call(cmdline):
|
||||
"""
|
||||
|
@ -223,7 +355,7 @@ CALL {cmdline}
|
|||
f.write(data)
|
||||
|
||||
try:
|
||||
out = call_command(fn)
|
||||
out = out_command(fn)
|
||||
# be vewwy vewwy caweful to print the env var as it might contain
|
||||
# secwet things like your pwecious pwivate key.
|
||||
# logger.debug("output of command:\n\n%s", out.decode('utf8', 'replace'))
|
||||
|
@ -307,20 +439,41 @@ def ensure_dir(dir):
|
|||
return dir
|
||||
|
||||
|
||||
def call_command(cmdline, output=True, **kwargs):
|
||||
def run_command(cmdline, **kwargs):
|
||||
logger.debug("calling command: %s", cmdline)
|
||||
if output:
|
||||
data = sp.check_output(cmdline, **kwargs)
|
||||
return data
|
||||
else:
|
||||
sp.check_call(cmdline, **kwargs)
|
||||
sp.check_call(cmdline, **kwargs)
|
||||
|
||||
|
||||
def out_command(cmdline, **kwargs):
|
||||
logger.debug("calling command: %s", cmdline)
|
||||
data = sp.check_output(cmdline, **kwargs)
|
||||
return data
|
||||
|
||||
|
||||
def setenv(k, v):
|
||||
logger.info("setting %s=%s", k, v)
|
||||
logger.debug("setting %s=%s", k, v)
|
||||
os.environ[k] = v
|
||||
|
||||
|
||||
def which(name):
|
||||
"""
|
||||
Return the full path of a command found on the path
|
||||
"""
|
||||
base, ext = os.path.splitext(name)
|
||||
if not ext:
|
||||
exts = ('.com', '.exe', '.bat', '.cmd')
|
||||
else:
|
||||
exts = (ext,)
|
||||
|
||||
for dir in ['.'] + os.environ['PATH'].split(os.pathsep):
|
||||
for ext in exts:
|
||||
fn = os.path.join(dir, base + ext)
|
||||
if os.path.isfile(fn):
|
||||
return fn
|
||||
|
||||
raise Exception("couldn't find program on path: %s" % name)
|
||||
|
||||
|
||||
def parse_cmdline():
|
||||
from argparse import ArgumentParser
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
|
||||
index dfd6972383..72d1259ffb 100644
|
||||
--- a/src/include/pg_config.h.win32
|
||||
+++ b/src/include/pg_config.h.win32
|
||||
@@ -74,12 +74,15 @@
|
||||
|
||||
/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */
|
||||
/* #undef HAVE_ASN1_STRING_GET0_DATA */
|
||||
+#define HAVE_ASN1_STRING_GET0_DATA 1
|
||||
|
||||
/* Define to 1 if you have the `BIO_get_data' function. */
|
||||
/* #undef HAVE_BIO_GET_DATA */
|
||||
+#define HAVE_BIO_GET_DATA 1
|
||||
|
||||
/* Define to 1 if you have the `BIO_meth_new' function. */
|
||||
/* #undef HAVE_BIO_METH_NEW */
|
||||
+#define HAVE_BIO_METH_NEW 1
|
||||
|
||||
/* Define to 1 if you have the `cbrt' function. */
|
||||
//#define HAVE_CBRT 1
|
Loading…
Reference in New Issue
Block a user