mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-02-17 01:20:32 +03:00
Build libpq from Python
This commit is contained in:
parent
73f6a0cd95
commit
c875197432
|
@ -85,60 +85,6 @@ init:
|
||||||
install:
|
install:
|
||||||
- "%PYEXE% C:\\appveyor.py 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
|
build: off
|
||||||
|
|
||||||
#before_build:
|
#before_build:
|
||||||
|
|
|
@ -95,15 +95,13 @@ def setup_env():
|
||||||
|
|
||||||
def python_info():
|
def python_info():
|
||||||
logger.info("Python Information")
|
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)
|
logger.info("%s", out)
|
||||||
|
|
||||||
cmdline = [
|
out = out_command(
|
||||||
py_exe(),
|
[py_exe(), '-c']
|
||||||
'-c',
|
+ ["import sys; print('64bit: %s' % (sys.maxsize > 2**32))"]
|
||||||
"import sys; print('64bit: %s' % (sys.maxsize > 2**32))",
|
)
|
||||||
]
|
|
||||||
out = call_command(cmdline)
|
|
||||||
logger.info("%s", out)
|
logger.info("%s", out)
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,12 +126,19 @@ def step_init():
|
||||||
|
|
||||||
|
|
||||||
def step_install():
|
def step_install():
|
||||||
build_openssl()
|
# TODO: enable again
|
||||||
|
# build_openssl()
|
||||||
|
build_libpq()
|
||||||
|
|
||||||
|
|
||||||
def build_openssl():
|
def build_openssl():
|
||||||
# Setup directories for building OpenSSL libraries
|
|
||||||
top = os.path.join(base_dir(), 'openssl')
|
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, 'include', 'openssl'))
|
||||||
ensure_dir(os.path.join(top, 'lib'))
|
ensure_dir(os.path.join(top, 'lib'))
|
||||||
|
|
||||||
|
@ -156,27 +161,16 @@ def build_openssl():
|
||||||
f"https://github.com/openssl/openssl/archive/{zipname}", zipfile
|
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:
|
with ZipFile(zipfile) as z:
|
||||||
z.extractall(path=build_dir())
|
z.extractall(path=build_dir())
|
||||||
|
|
||||||
os.chdir(os.path.join(build_dir(), f"openssl-OpenSSL_{ver}"))
|
os.chdir(os.path.join(build_dir(), f"openssl-OpenSSL_{ver}"))
|
||||||
cmdline = [
|
run_command(
|
||||||
'perl',
|
['perl', 'Configure', target, 'no-asm']
|
||||||
'Configure',
|
+ ['no-shared', 'no-zlib', f'--prefix={top}', f'--openssldir={top}']
|
||||||
target,
|
)
|
||||||
'no-asm',
|
|
||||||
'no-shared',
|
|
||||||
'no-zlib',
|
|
||||||
f'--prefix={top}',
|
|
||||||
f'--openssldir={top}',
|
|
||||||
]
|
|
||||||
call_command(cmdline, output=False)
|
|
||||||
|
|
||||||
cmdline = "nmake build_libs install_dev".split()
|
run_command("nmake build_libs install_dev".split())
|
||||||
call_command(cmdline, output=False)
|
|
||||||
|
|
||||||
assert os.path.exists(os.path.join(top, 'lib', 'libssl.lib'))
|
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}"))
|
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):
|
def download(url, fn):
|
||||||
"""Download a file locally"""
|
"""Download a file locally"""
|
||||||
|
logger.info("downloading %s", url)
|
||||||
with open(fn, 'wb') as fo, urlopen(url) as fi:
|
with open(fn, 'wb') as fo, urlopen(url) as fi:
|
||||||
while 1:
|
while 1:
|
||||||
data = fi.read(8192)
|
data = fi.read(8192)
|
||||||
|
@ -193,6 +294,37 @@ def download(url, fn):
|
||||||
break
|
break
|
||||||
fo.write(data)
|
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):
|
def bat_call(cmdline):
|
||||||
"""
|
"""
|
||||||
|
@ -223,7 +355,7 @@ CALL {cmdline}
|
||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out = call_command(fn)
|
out = out_command(fn)
|
||||||
# be vewwy vewwy caweful to print the env var as it might contain
|
# be vewwy vewwy caweful to print the env var as it might contain
|
||||||
# secwet things like your pwecious pwivate key.
|
# secwet things like your pwecious pwivate key.
|
||||||
# logger.debug("output of command:\n\n%s", out.decode('utf8', 'replace'))
|
# logger.debug("output of command:\n\n%s", out.decode('utf8', 'replace'))
|
||||||
|
@ -307,20 +439,41 @@ def ensure_dir(dir):
|
||||||
return dir
|
return dir
|
||||||
|
|
||||||
|
|
||||||
def call_command(cmdline, output=True, **kwargs):
|
def run_command(cmdline, **kwargs):
|
||||||
logger.debug("calling command: %s", cmdline)
|
logger.debug("calling command: %s", cmdline)
|
||||||
if output:
|
sp.check_call(cmdline, **kwargs)
|
||||||
data = sp.check_output(cmdline, **kwargs)
|
|
||||||
return data
|
|
||||||
else:
|
def out_command(cmdline, **kwargs):
|
||||||
sp.check_call(cmdline, **kwargs)
|
logger.debug("calling command: %s", cmdline)
|
||||||
|
data = sp.check_output(cmdline, **kwargs)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def setenv(k, v):
|
def setenv(k, v):
|
||||||
logger.info("setting %s=%s", k, v)
|
logger.debug("setting %s=%s", k, v)
|
||||||
os.environ[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():
|
def parse_cmdline():
|
||||||
from argparse import ArgumentParser
|
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