chore: directory structure

This commit is contained in:
2025-09-13 14:39:22 +08:00
parent 7b4bd2c68f
commit 4f629a9091
491 changed files with 716 additions and 49 deletions

4
pycdc/scripts/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
tarballs/
Python-*/
Python-*.conf.log
Python-*.build.log

View File

@@ -0,0 +1,42 @@
#
# This will generate a local container with the specified version of Python.
#
# Note: This assumes the the tarball for the particular version you'd like to build has already been downloaded,
# unpacked, and patched appropriately.
#
# To build:
# docker build --build-arg python_version=PYTHON-VERSION \
# --build-arg install_target=INSTALL-TARGET \
# -f Dockerfile.pybuild \
# -t python:PYTHON-VERSION
#
# PYTHON-VERSION full version of Python to build (ex. 3.0.1)
# INSTALL-TARGET the target to make for installing (fullinstall for 3.0.1, install otherwise)
#
# Example for 3.0.1:
# docker build --build-arg python_version=3.0.1 \
# --build-arg install_target=fullinstall \
# -f Dockerfile.pybuild \
# -t python:3.0.1
#
FROM debian:buster
ARG python_version
ARG install_target
RUN mkdir -p /pybuild/ &&\
apt-get update && \
apt-get upgrade -y && \
apt-get install -y build-essential libncurses-dev libz-dev libbz2-dev libreadline-dev
COPY Python-$python_version /pybuild/
RUN cd pybuild &&\
./configure && \
make && \
make $install_target && \
cd / && \
apt-get remove -y build-essential libncurses-dev libz-dev libbz2-dev libreadline-dev && \
apt autoremove -y && \
rm -rf /pybuild

357
pycdc/scripts/pymultic Normal file
View File

@@ -0,0 +1,357 @@
#!/usr/bin/env python3
# PyMultiC - Python Multiple Compiler
import os
import sys
import subprocess
import shutil
import re
PYVERS = {
'1.0': '1.0.1',
'1.1': '1.1',
'1.2': '1.2',
'1.3': '1.3',
'1.4': '1.4',
'1.5': '1.5.2',
'1.6': '1.6.1',
'2.0': '2.0.1',
'2.1': '2.1.3',
'2.2': '2.2.3',
'2.3': '2.3.7',
'2.4': '2.4.6',
'2.5': '2.5.6',
'2.6': '2.6.9',
'2.7': '2.7.18',
'3.0': '3.0.1',
'3.1': '3.1.5',
'3.2': '3.2.6',
'3.3': '3.3.7',
'3.4': '3.4.10',
'3.5': '3.5.10',
'3.6': '3.6.15',
'3.7': '3.7.17',
'3.8': '3.8.18',
'3.9': '3.9.18',
'3.10': '3.10.13',
'3.11': '3.11.6',
'3.12': '3.12.0',
}
OLD_PYTHONS = ('1.0', '1.1', '1.2', '1.3', '1.4', '1.5')
OLD_PYURL = 'https://legacy.python.org/download/releases/src'
PYURL = 'https://www.python.org/ftp/python'
# Not all versions of Python have an official container.
PYVER_CONTAINERS = {
'2.7',
'3.2',
'3.3',
'3.4',
'3.5',
'3.6',
'3.7',
'3.8',
'3.9',
'3.10',
'3.11',
'3.12',
}
CONTAINER_EXES = ['podman', 'docker']
CONTAINER_EXE_EXTRA_ARGS = {
'podman': [],
'docker': ['-u', '{}:{}'.format(os.getuid(), os.getgid())], # Docker requires extra magic for permissions.
}
def get_container_exe():
container_exe = None
for ce in CONTAINER_EXES:
if shutil.which(ce) is not None:
container_exe = ce
break
if container_exe is None:
print('Cannot find {} in $PATH'.format(' or '.join(CONTAINER_EXES)))
return sys.exit(1)
return container_exe
def fetch_python(snekdir, version):
realver = PYVERS[version]
if version in ('1.0', '1.1'):
tarball = 'python{}.tar.gz'.format(realver)
url = '{}/{}'.format(OLD_PYURL, tarball)
elif version in ('1.2', '1.3', '1.4', '1.5'):
tarball = 'python-{}.tar.gz'.format(realver)
url = '{}/{}'.format(OLD_PYURL, tarball)
elif version == '1.6':
tarball = 'Python-{}.tar.gz'.format(realver)
url = None
else:
tarball = 'Python-{}.tgz'.format(realver)
url = '{}/{}/{}'.format(PYURL, realver, tarball)
pyver_dir = os.path.join(snekdir, 'Python-{}'.format(realver))
if os.path.exists(pyver_dir):
return
tb_dir = os.path.join(snekdir, 'tarballs')
if not os.path.exists(tb_dir):
os.makedirs(tb_dir)
tarfile = os.path.join(tb_dir, tarball)
if not os.path.exists(tarfile):
if version == '1.6':
print('Python 1.6.1 cannot be downloaded automatically due to a license agreement')
print('which must be manually accepted.')
print('Please download it from https://www.python.org/download/releases/1.6.1/download/')
print('and place the tarball in {}'.format(tb_dir))
sys.exit(1)
print('Downloading Python {}...'.format(realver))
if subprocess.call(['curl', '-LfO#', url], cwd=tb_dir) != 0:
sys.exit(1)
print('Extracting Python {}...'.format(realver))
if subprocess.call(['tar', 'xaf', tarfile], cwd=snekdir) != 0:
sys.exit(1)
if os.path.exists(os.path.join(snekdir, 'python-{}'.format(realver))) \
and not os.path.exists(pyver_dir):
# The dual check prevents useless renames on case-insensitive
# file systems
os.rename(os.path.join(snekdir, 'python-{}'.format(realver)), pyver_dir)
patch_file = os.path.join(snekdir, 'python-builds', 'Python-{}.patch'.format(realver))
if os.path.exists(patch_file):
if subprocess.call(['patch', '-p1', '-i', patch_file], cwd=pyver_dir) != 0:
sys.exit(1)
def build_python(snekdir, version):
realver = PYVERS[version]
snek = 'Python-{}'.format(realver)
builddir = os.path.join(snekdir, snek)
# NOTE: This has only been tested on a Debian 10 x86_64 system -- it is
# probably not as robust as it should be...
print('Configuring Python {}...'.format(realver))
logfile = os.path.join(snekdir, '{}.conf.log'.format(snek))
with open(logfile, 'wb') as log:
if subprocess.call(['./configure'], stdout=log, stderr=log, cwd=builddir) != 0:
print('... Configuration failed. See {} for details'.format(logfile))
sys.exit(1)
print('Building Python {}...'.format(realver))
logfile = os.path.join(snekdir, '{}.build.log'.format(snek))
with open(logfile, 'wb') as log:
if subprocess.call(['make'], stdout=log, stderr=log, cwd=builddir) != 0:
print('... Build failed. See {} for details'.format(logfile))
sys.exit(1)
def acquire_python(snekdir, version):
snek = 'Python-{}'.format(PYVERS[version])
pyexe = os.path.join(snekdir, snek, 'python')
if not os.path.exists(pyexe):
fetch_python(snekdir, version)
build_python(snekdir, version)
return pyexe
def build_python_container(snekdir, version):
realver = PYVERS[version]
snek = 'Python-{}'.format(realver)
builddir = os.path.join(snekdir, snek)
container_exe = get_container_exe()
py_container_tag = 'python:{}'.format(realver)
if subprocess.call([container_exe, 'image', 'inspect', py_container_tag],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL) == 0:
return
fetch_python(snekdir, version)
print('Building Python {} container...'.format(realver))
logfile = os.path.join(snekdir, '{}.build.log'.format(snek))
install_target = 'fullinstall' if version == '3.0' else 'install'
with open(logfile, 'wb') as log:
if subprocess.call([container_exe, 'build',
'--build-arg', 'python_version={}'.format(realver),
'--build-arg', 'install_target={}'.format(install_target),
'-f', os.path.join(snekdir, 'Dockerfile.pybuild'),
'-t', py_container_tag, snekdir], stdout=log, stderr=log) != 0:
print('...Container build failed. See {} for details'.format(logfile))
sys.exit(1)
shutil.rmtree(builddir)
def local_compile(snekdir, ver, infile):
pyexe = acquire_python(snekdir, ver)
proc = subprocess.Popen([pyexe, '-c', 'import sys; print(sys.version)'],
stdout=subprocess.PIPE)
out, _ = proc.communicate()
if proc.returncode != 0:
print('Could not determine Python version for {}'.format(ver))
return None
bcver = str(out, 'iso-8859-1').split(' ', 1)[0]
if not bcver.startswith(ver):
print('Python {} reported itself as version {}!'.format(ver, bcver))
return None
if infile.endswith('.py'):
outfile = os.path.basename(infile)[:-3]
else:
outfile = os.path.basename(infile)
outfile += '.{}.pyc'.format(ver)
if os.path.exists(outfile):
os.unlink(outfile)
print('*** Compiling for Python {}'.format(bcver))
if ver in {'1.0', '1.1', '1.2', '1.3', '1.4'}:
# The hard way -- hope your code is safe...
srcdir = os.path.dirname(os.path.realpath(infile))
comptmp = os.path.join(srcdir, 'pymc_temp.py')
if os.path.exists(comptmp):
os.unlink(comptmp)
shutil.copyfile(infile, comptmp)
cwdsave = os.getcwd()
os.chdir(srcdir)
proc = subprocess.Popen([pyexe, '-c', 'import pymc_temp'])
proc.communicate()
os.chdir(cwdsave)
if os.path.exists(comptmp + 'o'):
shutil.copyfile(comptmp + 'o', outfile)
os.unlink(comptmp + 'o')
elif os.path.exists(comptmp + 'c'):
shutil.copyfile(comptmp + 'c', outfile)
os.unlink(comptmp + 'c')
os.unlink(comptmp)
else:
# The easy way
proc = subprocess.Popen([pyexe, '-c',
"import py_compile; py_compile.compile('{}', '{}')" \
.format(infile, outfile)])
proc.communicate()
return outfile
def container_compile(snekdir, ver, infile):
if ver not in PYVER_CONTAINERS:
build_python_container(snekdir, ver)
container_exe = get_container_exe()
fullver = PYVERS[ver]
indir = os.path.dirname(os.path.abspath(infile))
infile_full_path = infile
infile = os.path.basename(infile)
if infile.endswith('.py'):
outfile = infile[:-3]
else:
outfile = infile
outfile += '.{}.pyc'.format(ver)
if os.path.exists(outfile):
os.unlink(outfile)
print('*** Compiling for Python {}'.format(fullver))
if ver in {'1.0', '1.1', '1.2', '1.3', '1.4'}:
# The hard way -- hope your code is safe...
comptmp = os.path.join(indir, 'pymc_temp.py')
if os.path.exists(comptmp):
os.unlink(comptmp)
shutil.copyfile(infile_full_path, comptmp)
proc = subprocess.Popen([container_exe, 'run'] + CONTAINER_EXE_EXTRA_ARGS[container_exe] +
['--rm', '--name', outfile,
'-v', '{}:/indir:Z'.format(indir),
'-v', '{}:/outdir:Z'.format(os.getcwd()), '-w', '/outdir',
'-w', '/indir',
'python:{}'.format(fullver),
'python', '-c',
"import pymc_temp"])
proc.communicate()
if os.path.exists(comptmp + 'o'):
shutil.copyfile(comptmp + 'o', outfile)
os.unlink(comptmp + 'o')
elif os.path.exists(comptmp + 'c'):
shutil.copyfile(comptmp + 'c', outfile)
os.unlink(comptmp + 'c')
os.unlink(comptmp)
else:
# The easy way
proc = subprocess.Popen([container_exe, 'run'] + CONTAINER_EXE_EXTRA_ARGS[container_exe] +
['--rm', '--name', outfile,
'-v', '{}:/indir:Z'.format(indir),
'-v', '{}:/outdir:Z'.format(os.getcwd()), '-w', '/outdir',
'python:{}'.format(fullver),
'python', '-c',
"import py_compile; py_compile.compile('/indir/{}', '{}')".format(infile, outfile)])
proc.communicate()
return outfile
if len(sys.argv) < 2:
print('Usage: {} [-c] [versions] input.py'.format(sys.argv[0]))
print('Compile input.py for one or more python versions')
print()
print('-c\tuse prebuilt containers for running different versions of Python')
print('\t(not available for all versions)')
print()
print('Output is written to input.<version>.pyc for each version successfully compiled')
print()
print('Version is X.Y (e.g. 3.4), not including the patch version')
sys.exit(1)
RE_PYVER = re.compile(r'\d\.\d')
pythons = []
infile = None
use_containers = False
for arg in sys.argv[1:]:
if RE_PYVER.match(arg):
if arg in PYVERS.keys():
pythons.append(arg)
else:
print('Unknown Python version: {}'.format(arg))
sys.exit(1)
elif arg == '-c':
use_containers = True
elif arg.startswith('-'):
print("WARNING: Unrecognized argument '{}'".format(arg))
else:
infile = arg
if infile is None:
print('No input file specified')
sys.exit(1)
elif not os.path.exists(infile):
print('Error: Input file {} does not exist'.format(infile))
sys.exit(1)
if len(pythons) == 0:
print('At least one Python version is required')
sys.exit(1)
snekdir = os.path.dirname(os.path.realpath(__file__))
result = 0
for ver in pythons:
compile_with_container = use_containers
if use_containers and ver not in PYVER_CONTAINERS:
print('Warning: No officially supported container for {} - using locally built one'.format(ver))
outfile = None
if compile_with_container:
outfile = container_compile(snekdir, ver, infile)
else:
outfile = local_compile(snekdir, ver, infile)
if outfile is None or not os.path.exists(outfile):
result = 1
sys.exit(result)

View File

@@ -0,0 +1,40 @@
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index e79a671..b1bd74e 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -336,7 +336,7 @@ file_read(f, args)
*/
static object *
-getline(f, n)
+_py_getline(f, n)
fileobject *f;
int n;
{
@@ -458,7 +458,7 @@ filegetline(f, n)
}
if (((fileobject*)f)->f_fp == NULL)
return err_closed();
- return getline((fileobject *)f, n);
+ return _py_getline((fileobject *)f, n);
}
/* Python method */
@@ -483,7 +483,7 @@ file_readline(f, args)
}
}
- return getline(f, n);
+ return _py_getline(f, n);
}
static object *
@@ -501,7 +501,7 @@ file_readlines(f, args)
if ((list = newlistobject(0)) == NULL)
return NULL;
for (;;) {
- line = getline(f, 0);
+ line = _py_getline(f, 0);
if (line != NULL && getstringsize(line) == 0) {
DECREF(line);
break;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index b0eb332..e1aa559 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -587,7 +587,7 @@ file_readinto(f, args)
*/
static PyObject *
-getline(f, n)
+_py_getline(f, n)
PyFileObject *f;
int n;
{
@@ -709,7 +709,7 @@ PyFile_GetLine(f, n)
}
if (((PyFileObject*)f)->f_fp == NULL)
return err_closed();
- return getline((PyFileObject *)f, n);
+ return _py_getline((PyFileObject *)f, n);
}
/* Python method */
@@ -729,7 +729,7 @@ file_readline(f, args)
return PyString_FromString("");
if (n < 0)
n = 0;
- return getline(f, n);
+ return _py_getline(f, n);
}
static PyObject *
@@ -823,7 +823,7 @@ file_readlines(f, args)
goto error;
if (sizehint > 0) {
/* Need to complete the last line */
- PyObject *rest = getline(f, 0);
+ PyObject *rest = _py_getline(f, 0);
if (rest == NULL) {
Py_DECREF(line);
goto error;

View File

@@ -0,0 +1,34 @@
diff -rupN a/Include/objimpl.h b/Include/objimpl.h
--- a/Include/objimpl.h 2003-04-17 10:29:22.000000000 -0700
+++ b/Include/objimpl.h 2019-09-30 15:42:32.012660303 -0700
@@ -245,6 +245,20 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_R
/* for source compatibility with 2.2 */
#define _PyObject_GC_Del PyObject_GC_Del
+/*
+ * Former over-aligned definition of PyGC_Head, used to compute the size of the
+ * padding for the new version below.
+ */
+union _gc_head;
+union _gc_head_old {
+ struct {
+ union _gc_head_old *gc_next;
+ union _gc_head_old *gc_prev;
+ int gc_refs;
+ } gc;
+ long double dummy;
+};
+
/* GC information is stored BEFORE the object structure. */
typedef union _gc_head {
struct {
@@ -252,7 +266,8 @@ typedef union _gc_head {
union _gc_head *gc_prev;
int gc_refs;
} gc;
- long double dummy; /* force worst-case alignment */
+ double dummy; /* Force at least 8-byte alignment. */
+ char dummy_padding[sizeof(union _gc_head_old)];
} PyGC_Head;
extern PyGC_Head *_PyGC_generation0;

View File

@@ -0,0 +1,34 @@
diff -rupN a/Include/objimpl.h b/Include/objimpl.h
--- a/Include/objimpl.h 2003-04-17 10:29:22.000000000 -0700
+++ b/Include/objimpl.h 2019-09-30 15:42:32.012660303 -0700
@@ -245,6 +245,20 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_R
/* for source compatibility with 2.2 */
#define _PyObject_GC_Del PyObject_GC_Del
+/*
+ * Former over-aligned definition of PyGC_Head, used to compute the size of the
+ * padding for the new version below.
+ */
+union _gc_head;
+union _gc_head_old {
+ struct {
+ union _gc_head_old *gc_next;
+ union _gc_head_old *gc_prev;
+ int gc_refs;
+ } gc;
+ long double dummy;
+};
+
/* GC information is stored BEFORE the object structure. */
typedef union _gc_head {
struct {
@@ -252,7 +266,8 @@ typedef union _gc_head {
union _gc_head *gc_prev;
int gc_refs;
} gc;
- long double dummy; /* force worst-case alignment */
+ double dummy; /* Force at least 8-byte alignment. */
+ char dummy_padding[sizeof(union _gc_head_old)];
} PyGC_Head;
extern PyGC_Head *_PyGC_generation0;

View File

@@ -0,0 +1,83 @@
diff -rupN a/Include/objimpl.h b/Include/objimpl.h
--- a/Include/objimpl.h 2006-04-14 20:22:46.000000000 -0700
+++ b/Include/objimpl.h 2019-09-30 15:52:15.197269278 -0700
@@ -241,6 +241,20 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_R
/* for source compatibility with 2.2 */
#define _PyObject_GC_Del PyObject_GC_Del
+/*
+ * Former over-aligned definition of PyGC_Head, used to compute the size of the
+ * padding for the new version below.
+ */
+union _gc_head;
+union _gc_head_old {
+ struct {
+ union _gc_head_old *gc_next;
+ union _gc_head_old *gc_prev;
+ Py_ssize_t gc_refs;
+ } gc;
+ long double dummy;
+};
+
/* GC information is stored BEFORE the object structure. */
typedef union _gc_head {
struct {
@@ -248,7 +262,8 @@ typedef union _gc_head {
union _gc_head *gc_prev;
Py_ssize_t gc_refs;
} gc;
- long double dummy; /* force worst-case alignment */
+ double dummy; /* Force at least 8-byte alignment. */
+ char dummy_padding[sizeof(union _gc_head_old)];
} PyGC_Head;
extern PyGC_Head *_PyGC_generation0;
diff -rupN a/Makefile.pre.in b/Makefile.pre.in
--- a/Makefile.pre.in 2008-09-21 17:22:44.000000000 -0700
+++ b/Makefile.pre.in 2019-09-30 15:50:47.804578897 -0700
@@ -458,7 +458,7 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \
$(SIGNAL_OBJS) \
$(MODOBJS) \
$(srcdir)/Modules/getbuildinfo.c
- $(CC) -c $(PY_CFLAGS) -DSVNVERSION=\"`LC_ALL=C $(SVNVERSION)`\" -o $@ $(srcdir)/Modules/getbuildinfo.c
+ $(CC) -c $(PY_CFLAGS) -DSVNVERSION="\"`LC_ALL=C $(SVNVERSION)`\"" -o $@ $(srcdir)/Modules/getbuildinfo.c
Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
$(CC) -c $(PY_CFLAGS) -DPYTHONPATH='"$(PYTHONPATH)"' \
diff -rupN a/setup.py b/setup.py
--- a/setup.py 2008-10-16 11:58:19.000000000 -0700
+++ b/setup.py 2019-09-30 15:50:47.808578930 -0700
@@ -296,7 +296,8 @@ class PyBuildExt(build_ext):
# if a file is found in one of those directories, it can
# be assumed that no additional -I,-L directives are needed.
lib_dirs = self.compiler.library_dirs + [
- '/lib64', '/usr/lib64',
+ '/usr/lib/x86_64-linux-gnu',
+ '/lib/x86_64-linux-gnu',
'/lib', '/usr/lib',
]
inc_dirs = self.compiler.include_dirs + ['/usr/include']
@@ -711,9 +712,9 @@ class PyBuildExt(build_ext):
# check lib directories parallel to the location of the header
db_dirs_to_check = [
- os.path.join(db_incdir, '..', 'lib64'),
+ os.path.join(db_incdir, '..', 'lib/x86_64-linux-gnu'),
os.path.join(db_incdir, '..', 'lib'),
- os.path.join(db_incdir, '..', '..', 'lib64'),
+ os.path.join(db_incdir, '..', '..', 'lib/x86_64-linux-gnu'),
os.path.join(db_incdir, '..', '..', 'lib'),
]
db_dirs_to_check = filter(os.path.isdir, db_dirs_to_check)
@@ -800,9 +801,9 @@ class PyBuildExt(build_ext):
if sqlite_incdir:
sqlite_dirs_to_check = [
- os.path.join(sqlite_incdir, '..', 'lib64'),
+ os.path.join(sqlite_incdir, '..', 'lib/x86_64-linux-gnu'),
os.path.join(sqlite_incdir, '..', 'lib'),
- os.path.join(sqlite_incdir, '..', '..', 'lib64'),
+ os.path.join(sqlite_incdir, '..', '..', 'lib/x86_64-linux-gnu'),
os.path.join(sqlite_incdir, '..', '..', 'lib'),
]
sqlite_libfile = self.compiler.find_library_file(

View File

@@ -0,0 +1,68 @@
diff -rupN a/Include/objimpl.h b/Include/objimpl.h
--- a/Include/objimpl.h 2013-10-29 08:04:37.000000000 -0700
+++ b/Include/objimpl.h 2019-09-30 16:18:58.318197021 -0700
@@ -241,6 +241,20 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_R
/* for source compatibility with 2.2 */
#define _PyObject_GC_Del PyObject_GC_Del
+/*
+ * Former over-aligned definition of PyGC_Head, used to compute the size of the
+ * padding for the new version below.
+ */
+union _gc_head;
+union _gc_head_old {
+ struct {
+ union _gc_head_old *gc_next;
+ union _gc_head_old *gc_prev;
+ Py_ssize_t gc_refs;
+ } gc;
+ long double dummy;
+};
+
/* GC information is stored BEFORE the object structure. */
typedef union _gc_head {
struct {
@@ -248,7 +262,8 @@ typedef union _gc_head {
union _gc_head *gc_prev;
Py_ssize_t gc_refs;
} gc;
- long double dummy; /* force worst-case alignment */
+ double dummy; /* Force at least 8-byte alignment. */
+ char dummy_padding[sizeof(union _gc_head_old)];
} PyGC_Head;
extern PyGC_Head *_PyGC_generation0;
diff -rupN a/setup.py b/setup.py
--- a/setup.py 2013-10-29 08:04:39.000000000 -0700
+++ b/setup.py 2019-09-30 16:19:09.146284481 -0700
@@ -408,7 +408,8 @@ class PyBuildExt(build_ext):
# if a file is found in one of those directories, it can
# be assumed that no additional -I,-L directives are needed.
lib_dirs = self.compiler.library_dirs + [
- '/lib64', '/usr/lib64',
+ '/usr/lib/x86_64-linux-gnu',
+ '/lib/x86_64-linux-gnu',
'/lib', '/usr/lib',
]
inc_dirs = self.compiler.include_dirs + ['/usr/include']
@@ -922,7 +923,7 @@ class PyBuildExt(build_ext):
# check lib directories parallel to the location of the header
db_dirs_to_check = [
- db_incdir.replace("include", 'lib64'),
+ db_incdir.replace("include", 'lib/x86_64-linux-gnu'),
db_incdir.replace("include", 'lib'),
]
@@ -1034,9 +1035,9 @@ class PyBuildExt(build_ext):
if sqlite_incdir:
sqlite_dirs_to_check = [
- os.path.join(sqlite_incdir, '..', 'lib64'),
+ os.path.join(sqlite_incdir, '..', 'lib', 'x86_64-linux-gnu'),
os.path.join(sqlite_incdir, '..', 'lib'),
- os.path.join(sqlite_incdir, '..', '..', 'lib64'),
+ os.path.join(sqlite_incdir, '..', '..', 'lib', 'x86_64-linux-gnu'),
os.path.join(sqlite_incdir, '..', '..', 'lib'),
]
sqlite_libfile = self.compiler.find_library_file(

View File

@@ -0,0 +1,39 @@
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 4485a81..54a7e8d 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -499,7 +499,7 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \
$(SIGNAL_OBJS) \
$(MODOBJS) \
$(srcdir)/Modules/getbuildinfo.c
- $(CC) -c $(PY_CFLAGS) -DSVNVERSION=\"`LC_ALL=C $(SVNVERSION)`\" -o $@ $(srcdir)/Modules/getbuildinfo.c
+ $(CC) -c $(PY_CFLAGS) -DSVNVERSION="\"`LC_ALL=C $(SVNVERSION)`\"" -o $@ $(srcdir)/Modules/getbuildinfo.c
Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
$(CC) -c $(PY_CFLAGS) -DPYTHONPATH='"$(PYTHONPATH)"' \
diff --git a/setup.py b/setup.py
index e1d5984..9051d09 100644
--- a/setup.py
+++ b/setup.py
@@ -357,7 +357,8 @@ class PyBuildExt(build_ext):
# if a file is found in one of those directories, it can
# be assumed that no additional -I,-L directives are needed.
lib_dirs = self.compiler.library_dirs + [
- '/lib64', '/usr/lib64',
+ '/lib/x86_64-linux-gnu',
+ '/usr/lib/x86_64-linux-gnu',
'/lib', '/usr/lib',
]
inc_dirs = self.compiler.include_dirs + ['/usr/include']
@@ -725,9 +726,9 @@ class PyBuildExt(build_ext):
if sqlite_incdir:
sqlite_dirs_to_check = [
- os.path.join(sqlite_incdir, '..', 'lib64'),
+ os.path.join(sqlite_incdir, '..', 'lib', 'x86_64-linux-gnu'),
os.path.join(sqlite_incdir, '..', 'lib'),
- os.path.join(sqlite_incdir, '..', '..', 'lib64'),
+ os.path.join(sqlite_incdir, '..', '..', 'lib', 'x86_64-linux-gnu'),
os.path.join(sqlite_incdir, '..', '..', 'lib'),
]
sqlite_libfile = self.compiler.find_library_file(

View File

@@ -0,0 +1,16 @@
diff --git a/Makefile.pre.in b/Makefile.pre.in
index e01cd2745a..dcf465e30e 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -817,6 +817,11 @@ bininstall: altbininstall
else true; \
fi
(cd $(DESTDIR)$(BINDIR); $(LN) python$(VERSION)$(EXE) $(PYTHON)3$(EXE))
+ -if test -f $(DESTDIR)$(BINDIR)/$(PYTHON)$(EXE) -o -h $(DESTDIR)$(BINDIR)/$(PYTHON)$(EXE); \
+ then rm -f $(DESTDIR)$(BINDIR)/$(PYTHON)$(EXE); \
+ else true; \
+ fi
+ (cd $(DESTDIR)$(BINDIR); $(LN) python$(VERSION)$(EXE) $(PYTHON)$(EXE))
-rm -f $(DESTDIR)$(BINDIR)/python3-config
(cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)-config python3-config)
-rm -f $(DESTDIR)$(LIBPC)/python3.pc

270
pycdc/scripts/token_dump Normal file
View File

@@ -0,0 +1,270 @@
#!/usr/bin/env python3
# Compare two python source files by tokens, ignoring whitespace (other than
# indentation) and comments
import sys
import re
class PyToken:
INDENT = 1
OUTDENT = 2
ENDLINE = 3
WORD = 100
INT = 101
FLOAT = 102
STRING = 103
def __init__(self, type, n_line):
self.type = type
self.n_line = n_line
def __str__(self):
if self.type == PyToken.INDENT:
return '<INDENT>'
if self.type == PyToken.OUTDENT:
return '<OUTDENT>'
if self.type == PyToken.ENDLINE:
return '<EOL>'
return str(self.type)
def __eq__(self, other):
return self.type == other.type
class WordToken(PyToken):
# We don't need to distinguish between keywords and other words, so
# we just lump them together in a single token type...
def __init__(self, word, n_line):
super().__init__(PyToken.WORD, n_line)
self.word = word
def __str__(self):
return self.word
def __eq__(self, other):
if not super().__eq__(other):
return False
return self.word == other.word
class IntToken(PyToken):
def __init__(self, value, n_line):
super().__init__(PyToken.INT, n_line)
try:
self.value = int(value.replace('_', ''), 0)
except ValueError:
# Support Python 2.x octal literals
if value.startswith('0'):
self.value = int(value.replace('_', ''), 8)
else:
raise
def __str__(self):
return str(self.value)
def __eq__(self, other):
if not super().__eq__(other):
return False
return self.value == other.value
class FloatToken(PyToken):
def __init__(self, value, n_line):
super().__init__(PyToken.FLOAT, n_line)
self.value = float(value.replace('_', ''))
def __str__(self):
return str(self.value)
def __eq__(self, other):
if not super().__eq__(other):
return False
# TODO: Might need some fuzz
return self.value == other.value
class StringToken(PyToken):
def __init__(self, prefix, content, n_line):
super().__init__(PyToken.STRING, n_line)
# Normalize prefix for comparison
self.prefix = ''.join(sorted(prefix.lower()))
# Normalize special characters for comparison
self.content = content.replace("\\'", "'").replace("'", "\\'") \
.replace('\\"', '"').replace('\t', '\\t') \
.replace('\n', '\\n').replace('\r', '\\r')
def __str__(self):
return "{}'{}'".format(self.prefix, self.content)
def __eq__(self, other):
if not super().__eq__(other):
return False
return self.prefix == other.prefix and self.content == other.content
RE_WHITESPACE = re.compile(r'\s+')
RE_WORD = re.compile(r'[A-Za-z_][A-Za-z0-9_]*')
RE_INT = re.compile(r'[0-9][0-9_]*|0[Xx][0-9A-Fa-f_]+|0[Bb][0-1_]+|0[Oo][0-7_]+')
RE_FLOAT = re.compile(r'(([0-9][0-9_]*)?\.[0-9][0-9_]*|[0-9][0-9_]*\.)([eE][+-]?[0-9][0-9_]*)?')
RE_START_STRING = re.compile(r'([rR][fFbB]?|[uU]|[fF][rR]?|[bB][rR]?)?(\'\'\'|\'|"""|")')
# Note, tokens sharing a common prefix should be entered in order from
# longest to shortest, so we don't mismatch a long token as a sequence
# of shorter tokens
SYMBOLIC_TOKENS = (
'<<=', '>>=', '**=', '//=', '...', '.',
'+=', '-=', '*=', '@=', '/=', '%=', '&=', '|=', '^=',
'<>', '<<', '<=', '<', '>>', '>=', '>', '!=', '==', '=',
',', ';', ':=', ':', '->', '~', '`',
'+', '-', '**', '*', '@', '//', '/', '%', '&', '|', '^',
'(', ')', '{', '}', '[', ']',
)
def symbolic_token(line, n_line):
for tok in SYMBOLIC_TOKENS:
if line.startswith(tok):
return PyToken(tok, n_line)
return None
def string_token(line, n_line, pysrc):
match = RE_START_STRING.match(line)
if not match:
return None
# Look for the end of the string
prefix = match.group(1)
if prefix is None:
prefix = ''
quotes = match.group(2)
start = len(prefix) + len(quotes)
content = ''
while True:
end = line.find(quotes, start)
if end > 0 and line[end - 1] == '\\':
content += line[start:end + 1]
start = end + 1
continue
elif end >= 0:
content += line[start:end]
break
# Read in a new line
content += line[start:]
line = pysrc.readline()
n_line += 1
start = 0
if not line:
raise RuntimeError('Reached EOF while looking for {}'.format(repr(quotes)))
token = StringToken(prefix, content, n_line)
token.rem_line = line[end + len(quotes):]
token.end_line = n_line
return token
def read_tokens(pysrc):
indent_stack = [0]
context_stack = []
n_line = 0
while True:
line = pysrc.readline()
n_line += 1
if not line:
break
if not line.strip() or line.lstrip().startswith('#'):
continue
# Look for indentation changes
if len(context_stack) == 0:
indent = len(line) - len(line.lstrip())
if indent > indent_stack[-1]:
indent_stack.append(indent)
yield PyToken(PyToken.INDENT, n_line)
while indent < indent_stack[-1]:
indent_stack.pop()
yield PyToken(PyToken.OUTDENT, n_line)
if indent != indent_stack[-1]:
raise RuntimeError('Incorrect indentation on line {}'.format(n_line))
while True:
line = line.lstrip()
if not line:
break
if line[0] == '#':
# The rest of this line is a comment
break
token = symbolic_token(line, n_line)
if token:
if token.type in {'(', '{', '['}:
context_stack.append(token.type)
elif token.type == ')':
if len(context_stack) == 0 or context_stack[-1] != '(':
raise RuntimeError('Mismatched token at {} on line {}'.format(line, n_line))
context_stack.pop()
elif token.type == '}':
if len(context_stack) == 0 or context_stack[-1] != '{':
raise RuntimeError('Mismatched token at {} on line {}'.format(line, n_line))
context_stack.pop()
elif token.type == ']':
if len(context_stack) == 0 or context_stack[-1] != '[':
raise RuntimeError('Mismatched token at {} on line {}'.format(line, n_line))
context_stack.pop()
yield token
line = line[len(token.type):]
continue
match = RE_FLOAT.match(line)
if match:
yield FloatToken(match.group(), n_line)
line = line[match.end():]
continue
match = RE_INT.match(line)
if match:
yield IntToken(match.group(), n_line)
line = line[match.end():]
continue
token = string_token(line, n_line, pysrc)
if token:
line = token.rem_line
n_line = token.end_line
yield token
continue
match = RE_WORD.match(line)
if match:
yield WordToken(match.group(), n_line)
line = line[match.end():]
continue
raise RuntimeError('Error: Unrecognized tokens: "{}" at line {}'.format(line, n_line))
if len(context_stack) == 0:
yield PyToken(PyToken.ENDLINE, n_line)
if __name__ == '__main__':
if '--help' in sys.argv:
print('Usage: token_dump <file>.py')
sys.exit(0)
if len(sys.argv) >= 2:
pysrc = open(sys.argv[1], 'r')
else:
pysrc = sys.stdin
for tok in read_tokens(pysrc):
if tok.type in {PyToken.ENDLINE, PyToken.INDENT, PyToken.OUTDENT}:
print(tok)
else:
print(tok, end=' ')
pysrc.close()