2021-09-04 22:44:00 +00:00
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
|
|
|
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
|
|
|
│ │
|
|
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
|
|
│ │
|
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
|
|
#include "libc/assert.h"
|
|
|
|
#include "libc/calls/calls.h"
|
|
|
|
#include "libc/calls/struct/iovec.h"
|
|
|
|
#include "libc/calls/struct/stat.h"
|
|
|
|
#include "libc/elf/def.h"
|
|
|
|
#include "libc/fmt/conv.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
#include "libc/intrin/bits.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "libc/log/check.h"
|
|
|
|
#include "libc/log/log.h"
|
2021-09-05 08:20:03 +00:00
|
|
|
#include "libc/macros.internal.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
#include "libc/mem/gc.internal.h"
|
2021-09-13 04:04:44 +00:00
|
|
|
#include "libc/mem/mem.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "libc/runtime/runtime.h"
|
2023-09-07 12:39:58 +00:00
|
|
|
#include "libc/runtime/stack.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
#include "libc/stdio/append.h"
|
2021-09-13 04:04:44 +00:00
|
|
|
#include "libc/stdio/stdio.h"
|
2022-03-16 23:59:45 +00:00
|
|
|
#include "libc/sysv/consts/clock.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "libc/sysv/consts/o.h"
|
2022-03-16 23:59:45 +00:00
|
|
|
#include "libc/time/time.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "libc/x/x.h"
|
2023-06-10 01:02:06 +00:00
|
|
|
#include "libc/zip.internal.h"
|
2023-07-03 02:57:43 +00:00
|
|
|
#include "third_party/getopt/getopt.internal.h"
|
2021-09-07 02:24:10 +00:00
|
|
|
#include "third_party/python/Include/abstract.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/bytesobject.h"
|
2021-09-07 02:24:10 +00:00
|
|
|
#include "third_party/python/Include/code.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/compile.h"
|
2021-09-13 04:04:44 +00:00
|
|
|
#include "third_party/python/Include/dictobject.h"
|
|
|
|
#include "third_party/python/Include/fileobject.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/fileutils.h"
|
2021-09-13 04:04:44 +00:00
|
|
|
#include "third_party/python/Include/grammar.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/import.h"
|
2021-09-05 08:20:03 +00:00
|
|
|
#include "third_party/python/Include/longobject.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/marshal.h"
|
2021-09-13 04:04:44 +00:00
|
|
|
#include "third_party/python/Include/modsupport.h"
|
|
|
|
#include "third_party/python/Include/objimpl.h"
|
2021-09-05 08:20:03 +00:00
|
|
|
#include "third_party/python/Include/opcode.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/pydebug.h"
|
2021-10-02 13:17:17 +00:00
|
|
|
#include "third_party/python/Include/pyerrors.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "third_party/python/Include/pylifecycle.h"
|
|
|
|
#include "third_party/python/Include/pymacro.h"
|
|
|
|
#include "third_party/python/Include/pythonrun.h"
|
2021-09-13 04:04:44 +00:00
|
|
|
#include "third_party/python/Include/sysmodule.h"
|
2021-09-05 08:20:03 +00:00
|
|
|
#include "third_party/python/Include/tupleobject.h"
|
|
|
|
#include "third_party/python/Include/unicodeobject.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "tool/build/lib/elfwriter.h"
|
2021-09-07 02:24:10 +00:00
|
|
|
#include "tool/build/lib/interner.h"
|
2021-09-04 22:44:00 +00:00
|
|
|
#include "tool/build/lib/stripcomponents.h"
|
|
|
|
/* clang-format off */
|
|
|
|
|
2023-09-07 12:39:58 +00:00
|
|
|
STATIC_STACK_ALIGN(GetStackSize());
|
|
|
|
|
2023-07-26 20:54:49 +00:00
|
|
|
__static_yoink("_PyUnicode_GetCode");
|
2021-09-28 05:58:51 +00:00
|
|
|
|
2021-09-04 22:44:00 +00:00
|
|
|
#define MANUAL "\
|
|
|
|
SYNOPSIS\n\
|
|
|
|
\n\
|
|
|
|
pyobj.com [FLAGS] SOURCE\n\
|
|
|
|
\n\
|
|
|
|
OVERVIEW\n\
|
|
|
|
\n\
|
|
|
|
Python Objectifier\n\
|
|
|
|
\n\
|
|
|
|
FLAGS\n\
|
|
|
|
\n\
|
|
|
|
-o PATH output elf object file\n\
|
2021-09-12 05:30:37 +00:00
|
|
|
-P STR prefix fake zip directory (default .python)\n\
|
2021-09-04 22:44:00 +00:00
|
|
|
-C INT strip directory components from src in zip\n\
|
2021-09-13 04:04:44 +00:00
|
|
|
-Y SYM append yoink to elf object [repeatable]\n\
|
2021-09-04 22:44:00 +00:00
|
|
|
-O0 don't optimize [default]\n\
|
|
|
|
-O1 remove debug statements\n\
|
|
|
|
-O2 remove debug statements and docstrings\n\
|
2021-09-07 02:34:57 +00:00
|
|
|
-B binary only (don't include .py file)\n\
|
2021-09-13 04:04:44 +00:00
|
|
|
-m insert executable launch.c main\n\
|
|
|
|
-r insert executable repl.c main\n\
|
2021-09-28 05:58:51 +00:00
|
|
|
-t insert unit test framework\n\
|
2021-09-04 22:44:00 +00:00
|
|
|
-0 zip uncompressed\n\
|
|
|
|
-n do nothing\n\
|
|
|
|
-h help\n\
|
|
|
|
\n"
|
|
|
|
|
2021-09-07 18:40:11 +00:00
|
|
|
const char *const kIgnoredModules[] = /* sorted */ {
|
2021-09-05 08:20:03 +00:00
|
|
|
"__main__", /* todo? */
|
|
|
|
"_dummy_threading", /* evil code */
|
2021-09-07 02:24:10 +00:00
|
|
|
"_dummy_threading.Thread",
|
|
|
|
"_dummy_threading.__all__",
|
2021-09-05 08:20:03 +00:00
|
|
|
"_overlapped", /* don't recognize if sys.platform yet */
|
|
|
|
"_scproxy", /* don't recognize if sys.platform yet */
|
|
|
|
"_winapi", /* don't recognize if sys.platform yet */
|
|
|
|
"asyncio.test_support", /* todo??? */
|
|
|
|
"builtins",
|
|
|
|
"concurrent.futures", /* asyncio's fault */
|
|
|
|
"concurrent.futures._base",
|
|
|
|
"concurrent.futures.process",
|
2021-09-07 02:24:10 +00:00
|
|
|
"distutils.command.bdist",
|
|
|
|
"distutils.command.bdist_dumb",
|
|
|
|
"distutils.command.bdist_rpm",
|
|
|
|
"distutils.command.bdist_wininst",
|
|
|
|
"distutils.command.build",
|
|
|
|
"distutils.command.build_clib",
|
|
|
|
"distutils.command.build_ext",
|
|
|
|
"distutils.command.build_py",
|
|
|
|
"distutils.command.build_scripts",
|
|
|
|
"distutils.command.check",
|
|
|
|
"distutils.command.clean",
|
|
|
|
"distutils.command.install",
|
|
|
|
"distutils.command.install_data",
|
|
|
|
"distutils.command.install_headers",
|
|
|
|
"distutils.command.install_lib",
|
|
|
|
"distutils.command.install_scripts",
|
|
|
|
"distutils.command.register",
|
|
|
|
"distutils.command.sdist",
|
|
|
|
"distutils.command.upload",
|
|
|
|
"distutils.spawn._nt_quote_args",
|
2021-09-13 04:04:44 +00:00
|
|
|
"encodings.aliases",
|
2021-09-07 02:24:10 +00:00
|
|
|
"importlib._bootstrap",
|
|
|
|
"importlib._bootstrap.BuiltinImporter",
|
|
|
|
"importlib._bootstrap.FrozenImporter",
|
|
|
|
"importlib._bootstrap.ModuleSpec",
|
|
|
|
"importlib._bootstrap._ERR_MSG",
|
|
|
|
"importlib._bootstrap.__import__",
|
|
|
|
"importlib._bootstrap._builtin_from_name",
|
|
|
|
"importlib._bootstrap._exec",
|
|
|
|
"importlib._bootstrap._find_spec",
|
|
|
|
"importlib._bootstrap._load",
|
|
|
|
"importlib._bootstrap._resolve_name",
|
|
|
|
"importlib._bootstrap.module_from_spec",
|
|
|
|
"importlib._bootstrap.spec_from_loader",
|
|
|
|
"importlib._bootstrap_external",
|
|
|
|
"importlib._bootstrap_external.BYTECODE_SUFFIXES",
|
|
|
|
"importlib._bootstrap_external.DEBUG_BYTECODE_SUFFIXES",
|
|
|
|
"importlib._bootstrap_external.EXTENSION_SUFFIXES",
|
|
|
|
"importlib._bootstrap_external.ExtensionFileLoader",
|
|
|
|
"importlib._bootstrap_external.FileFinder",
|
|
|
|
"importlib._bootstrap_external.MAGIC_NUMBER",
|
|
|
|
"importlib._bootstrap_external.OPTIMIZED_BYTECODE_SUFFIXES",
|
|
|
|
"importlib._bootstrap_external.PathFinder",
|
|
|
|
"importlib._bootstrap_external.SOURCE_SUFFIXES",
|
|
|
|
"importlib._bootstrap_external.SourceFileLoader",
|
|
|
|
"importlib._bootstrap_external.SourcelessFileLoader",
|
|
|
|
"importlib._bootstrap_external.WindowsRegistryFinder",
|
|
|
|
"importlib._bootstrap_external.cache_from_source",
|
|
|
|
"importlib._bootstrap_external.decode_source",
|
|
|
|
"importlib._bootstrap_external.source_from_cache",
|
|
|
|
"importlib._bootstrap_external.spec_from_file_location",
|
2021-09-05 08:20:03 +00:00
|
|
|
"java", /* don't recognize if sys.platform yet */
|
|
|
|
"java.lang", /* don't recognize if sys.platform yet */
|
|
|
|
"msvcrt", /* don't recognize if sys.platform yet */
|
2021-09-07 02:24:10 +00:00
|
|
|
"msvcrt.setmode", /* don't recognize if sys.platform yet */
|
2021-09-05 08:20:03 +00:00
|
|
|
"nt", /* os module don't care */
|
2021-09-07 02:24:10 +00:00
|
|
|
"nt._getfinalpathname",
|
|
|
|
"os.path",
|
|
|
|
"os.path._get_sep",
|
|
|
|
"os.path._joinrealpath",
|
|
|
|
"os.path._varprog",
|
|
|
|
"os.path._varprogb",
|
|
|
|
"os.path.abspath",
|
|
|
|
"os.path.altsep",
|
|
|
|
"os.path.basename",
|
|
|
|
"os.path.commonpath",
|
|
|
|
"os.path.commonprefix",
|
|
|
|
"os.path.curdir",
|
|
|
|
"os.path.defpath",
|
|
|
|
"os.path.devnull",
|
|
|
|
"os.path.dirname",
|
|
|
|
"os.path.exists",
|
|
|
|
"os.path.expanduser",
|
|
|
|
"os.path.expandvars",
|
|
|
|
"os.path.extsep",
|
|
|
|
"os.path.genericpath",
|
|
|
|
"os.path.getatime",
|
|
|
|
"os.path.getctime",
|
|
|
|
"os.path.getmtime",
|
|
|
|
"os.path.getsize",
|
|
|
|
"os.path.isabs",
|
|
|
|
"os.path.isdir",
|
|
|
|
"os.path.isfile",
|
|
|
|
"os.path.islink",
|
|
|
|
"os.path.ismount",
|
|
|
|
"os.path.join",
|
|
|
|
"os.path.lexists",
|
|
|
|
"os.path.normcase",
|
|
|
|
"os.path.normpath",
|
|
|
|
"os.path.os",
|
|
|
|
"os.path.pardir",
|
|
|
|
"os.path.pathsep",
|
|
|
|
"os.path.realpath",
|
|
|
|
"os.path.relpath",
|
|
|
|
"os.path.samefile",
|
|
|
|
"os.path.sameopenfile",
|
|
|
|
"os.path.samestat",
|
|
|
|
"os.path.sep",
|
|
|
|
"os.path.split",
|
|
|
|
"os.path.splitdrive",
|
|
|
|
"os.path.splitext",
|
|
|
|
"os.path.stat",
|
|
|
|
"os.path.supports_unicode_filenames",
|
|
|
|
"os.path.sys",
|
2021-09-05 08:20:03 +00:00
|
|
|
"sys",
|
2021-09-07 02:24:10 +00:00
|
|
|
"test.libregrtest.main",
|
2021-09-28 05:58:51 +00:00
|
|
|
/* "xml.dom", */
|
2021-09-05 08:20:03 +00:00
|
|
|
};
|
|
|
|
|
2021-09-13 04:04:44 +00:00
|
|
|
struct Yoinks {
|
|
|
|
size_t n;
|
|
|
|
char **p;
|
|
|
|
} yoinks;
|
|
|
|
|
2021-09-05 08:20:03 +00:00
|
|
|
static bool binonly;
|
|
|
|
static int optimize;
|
|
|
|
static char *pyfile;
|
|
|
|
static char *outpath;
|
|
|
|
static struct stat st;
|
|
|
|
static PyObject *code;
|
|
|
|
static PyObject *marsh;
|
|
|
|
static bool nocompress;
|
2021-09-28 05:58:51 +00:00
|
|
|
static bool isunittest;
|
2021-09-13 04:04:44 +00:00
|
|
|
static bool insertrunner;
|
2021-09-12 05:30:37 +00:00
|
|
|
static bool insertlauncher;
|
2021-09-05 08:20:03 +00:00
|
|
|
static int strip_components;
|
|
|
|
static struct ElfWriter *elf;
|
|
|
|
static const char *path_prefix;
|
2021-09-07 02:24:10 +00:00
|
|
|
static struct Interner *yoinked;
|
2021-09-05 08:20:03 +00:00
|
|
|
static struct timespec timestamp;
|
2021-09-13 04:04:44 +00:00
|
|
|
static struct Interner *forcepulls;
|
2021-09-04 22:44:00 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
GetOpts(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int opt;
|
2021-09-12 05:30:37 +00:00
|
|
|
path_prefix = ".python";
|
2021-09-28 05:58:51 +00:00
|
|
|
while ((opt = getopt(argc, argv, "hnmtr0Bb:O:o:C:P:Y:")) != -1) {
|
2021-09-04 22:44:00 +00:00
|
|
|
switch (opt) {
|
2021-09-07 02:24:10 +00:00
|
|
|
case 'B':
|
|
|
|
binonly = true;
|
|
|
|
break;
|
2021-09-28 05:58:51 +00:00
|
|
|
case 't':
|
|
|
|
isunittest = true;
|
|
|
|
break;
|
2021-09-07 02:24:10 +00:00
|
|
|
case '0':
|
|
|
|
nocompress = true;
|
2021-09-04 22:44:00 +00:00
|
|
|
break;
|
2021-09-13 04:04:44 +00:00
|
|
|
case 'r':
|
|
|
|
insertrunner = true;
|
|
|
|
insertlauncher = false;
|
|
|
|
break;
|
2021-09-12 05:30:37 +00:00
|
|
|
case 'm':
|
2021-09-13 04:04:44 +00:00
|
|
|
insertrunner = false;
|
2021-09-12 05:30:37 +00:00
|
|
|
insertlauncher = true;
|
|
|
|
break;
|
2021-09-04 22:44:00 +00:00
|
|
|
case 'o':
|
|
|
|
outpath = optarg;
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
path_prefix = optarg;
|
|
|
|
break;
|
2021-09-07 02:24:10 +00:00
|
|
|
case 'O':
|
|
|
|
optimize = atoi(optarg);
|
|
|
|
break;
|
2021-09-04 22:44:00 +00:00
|
|
|
case 'C':
|
2021-09-07 02:24:10 +00:00
|
|
|
strip_components = atoi(optarg);
|
2021-09-04 22:44:00 +00:00
|
|
|
break;
|
2021-09-13 04:04:44 +00:00
|
|
|
case 'Y':
|
|
|
|
yoinks.p = realloc(yoinks.p, ++yoinks.n * sizeof(*yoinks.p));
|
2021-10-02 13:17:17 +00:00
|
|
|
yoinks.p[yoinks.n - 1] = xstrdup(optarg);
|
2021-09-13 04:04:44 +00:00
|
|
|
break;
|
2021-09-04 22:44:00 +00:00
|
|
|
case 'n':
|
|
|
|
exit(0);
|
|
|
|
case 'h':
|
|
|
|
fputs(MANUAL, stdout);
|
|
|
|
exit(0);
|
|
|
|
default:
|
|
|
|
fputs(MANUAL, stderr);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (argc - optind != 1) {
|
|
|
|
fputs("error: need one input file\n", stderr);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
pyfile = argv[optind];
|
2021-09-05 08:20:03 +00:00
|
|
|
if (stat(pyfile, &st)) {
|
|
|
|
perror(pyfile);
|
|
|
|
exit(1);
|
|
|
|
}
|
2021-09-04 22:44:00 +00:00
|
|
|
if (!outpath) {
|
|
|
|
outpath = xstrcat(pyfile, ".o");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
Dotify(char *s)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; s[i]; ++i) {
|
|
|
|
if (s[i] == '/') {
|
|
|
|
s[i] = '.';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
GetZipFile(void)
|
|
|
|
{
|
|
|
|
const char *zipfile;
|
|
|
|
zipfile = pyfile;
|
|
|
|
zipfile = StripComponents(zipfile, strip_components);
|
2021-09-12 05:30:37 +00:00
|
|
|
if (*path_prefix) {
|
2021-09-04 22:44:00 +00:00
|
|
|
zipfile = gc(xjoinpaths(path_prefix, zipfile));
|
|
|
|
}
|
2021-10-02 13:17:17 +00:00
|
|
|
return xstrdup(zipfile);
|
2021-09-04 22:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
GetZipDir(void)
|
|
|
|
{
|
|
|
|
return xstrcat(gc(xdirname(gc(GetZipFile()))), '/');
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
GetSynFile(void)
|
|
|
|
{
|
|
|
|
return xstrcat("/zip/", gc(GetZipFile()));
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
GetModName(bool *ispkg)
|
|
|
|
{
|
|
|
|
char *mod;
|
|
|
|
mod = Dotify(xstripexts(StripComponents(pyfile, strip_components)));
|
2023-08-14 03:31:27 +00:00
|
|
|
if ((*ispkg = endswith(mod, ".__init__"))) {
|
2021-09-04 22:44:00 +00:00
|
|
|
mod[strlen(mod) - strlen(".__init__")] = 0;
|
|
|
|
}
|
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
2021-09-07 02:24:10 +00:00
|
|
|
static bool
|
|
|
|
IsDot(void)
|
|
|
|
{
|
|
|
|
bool res;
|
|
|
|
char *mod;
|
|
|
|
mod = Dotify(xstripexts(StripComponents(pyfile, strip_components)));
|
|
|
|
res = !!strchr(mod, '.');
|
|
|
|
free(mod);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
GetParent(void)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
p = Dotify(xstripexts(StripComponents(pyfile, strip_components)));
|
|
|
|
*strrchr(p, '.') = 0;
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2021-09-13 04:04:44 +00:00
|
|
|
static char *
|
|
|
|
GetParent2(void)
|
|
|
|
{
|
|
|
|
char *p, *mod;
|
|
|
|
mod = Dotify(xstripexts(StripComponents(pyfile, strip_components)));
|
2023-08-14 03:31:27 +00:00
|
|
|
if (endswith(mod, ".__init__")) mod[strlen(mod) - strlen(".__init__")] = 0;
|
2021-09-13 04:04:44 +00:00
|
|
|
if ((p = strrchr(mod, '.'))) *p = 0;
|
|
|
|
return mod;
|
|
|
|
}
|
|
|
|
|
2021-09-05 08:20:03 +00:00
|
|
|
static char *
|
2021-10-02 13:17:17 +00:00
|
|
|
GetModSibling(const char *rel, long chomp)
|
2021-09-05 08:20:03 +00:00
|
|
|
{
|
|
|
|
char *p, *mod, *sib;
|
|
|
|
mod = Dotify(xstripexts(StripComponents(pyfile, strip_components)));
|
2021-10-02 13:17:17 +00:00
|
|
|
while (chomp-- > 0) {
|
2021-09-07 02:24:10 +00:00
|
|
|
if ((p = strrchr(mod, '.'))) {
|
|
|
|
*p = 0;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rel) {
|
|
|
|
if (*mod) {
|
|
|
|
sib = xstrcat(mod, '.', rel);
|
|
|
|
} else {
|
2021-10-02 13:17:17 +00:00
|
|
|
sib = xstrdup(rel);
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
2021-09-05 08:20:03 +00:00
|
|
|
} else {
|
2021-10-02 13:17:17 +00:00
|
|
|
sib = xstrdup(mod);
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
|
|
|
free(mod);
|
|
|
|
return sib;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
IsIgnoredModule(const char *s)
|
|
|
|
{
|
|
|
|
int m, l, r, x;
|
|
|
|
l = 0;
|
|
|
|
r = ARRAYLEN(kIgnoredModules) - 1;
|
|
|
|
while (l <= r) {
|
2023-07-10 17:16:55 +00:00
|
|
|
m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2)
|
2021-09-05 08:20:03 +00:00
|
|
|
x = strcmp(s, kIgnoredModules[m]);
|
|
|
|
if (x < 0) {
|
|
|
|
r = m - 1;
|
|
|
|
} else if (x > 0) {
|
|
|
|
l = m + 1;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-09-13 04:04:44 +00:00
|
|
|
Yoink(const char *name)
|
2021-09-07 02:24:10 +00:00
|
|
|
{
|
2021-09-13 04:04:44 +00:00
|
|
|
if (!isinterned(yoinked, name) && !IsIgnoredModule(name)) {
|
2021-09-07 02:24:10 +00:00
|
|
|
intern(yoinked, name);
|
2021-09-13 04:04:44 +00:00
|
|
|
/* elfwriter_yoink(elf, gc(xstrcat("pyc:", name)), STB_WEAK); */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Forcepull(const char *name)
|
|
|
|
{
|
|
|
|
if (!isinterned(forcepulls, name) && !IsIgnoredModule(name)) {
|
|
|
|
intern(yoinked, name);
|
|
|
|
intern(forcepulls, name);
|
|
|
|
elfwriter_yoink(elf, gc(xstrcat("pyc:", name)), STB_GLOBAL);
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
Provide(const char *modname, const char *global)
|
|
|
|
{
|
|
|
|
char *imp, *symbol;
|
|
|
|
imp = xstrcat(modname, '.', global);
|
2021-09-13 04:04:44 +00:00
|
|
|
if ((!isinterned(forcepulls, imp) &&
|
|
|
|
!isinterned(yoinked, imp) &&
|
|
|
|
!IsIgnoredModule(imp))) {
|
2021-09-07 02:24:10 +00:00
|
|
|
symbol = xstrcat("pyc:", imp);
|
|
|
|
elfwriter_appendsym(elf, symbol,
|
|
|
|
ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
|
|
|
STV_DEFAULT, 0, 0);
|
|
|
|
free(symbol);
|
|
|
|
}
|
|
|
|
free(imp);
|
|
|
|
}
|
|
|
|
|
2021-10-02 13:17:17 +00:00
|
|
|
static int
|
2021-09-07 02:24:10 +00:00
|
|
|
Analyze(const char *modname, PyObject *code, struct Interner *globals)
|
2021-09-05 08:20:03 +00:00
|
|
|
{
|
2021-10-02 13:17:17 +00:00
|
|
|
int rc;
|
2021-09-07 02:24:10 +00:00
|
|
|
bool istry;
|
|
|
|
unsigned a;
|
2023-09-02 03:49:13 +00:00
|
|
|
size_t i, n;
|
2021-09-07 02:24:10 +00:00
|
|
|
char *p, *mod, *imp;
|
|
|
|
int x, y, op, arg, rel;
|
2021-10-02 13:17:17 +00:00
|
|
|
PyObject *co_code, *co_names, *co_consts, *name, *iter, *item;
|
|
|
|
rc = 0;
|
2021-09-07 02:24:10 +00:00
|
|
|
mod = 0;
|
2023-09-02 03:49:13 +00:00
|
|
|
istry = (rel = 0);
|
2021-09-12 05:30:37 +00:00
|
|
|
assert(PyCode_Check(code));
|
|
|
|
co_code = ((PyCodeObject *)code)->co_code;
|
|
|
|
co_names = ((PyCodeObject *)code)->co_names;
|
|
|
|
co_consts = ((PyCodeObject *)code)->co_consts;
|
2021-09-05 08:20:03 +00:00
|
|
|
n = PyBytes_GET_SIZE(co_code);
|
|
|
|
p = PyBytes_AS_STRING(co_code);
|
2021-10-02 13:17:17 +00:00
|
|
|
for (a = i = 0; !rc && i + 2 <= n; i += 2) {
|
2021-09-05 08:20:03 +00:00
|
|
|
x = p[i + 0] & 255;
|
|
|
|
y = p[i + 1] & 255;
|
2021-09-07 02:24:10 +00:00
|
|
|
a = a << 8 | y;
|
|
|
|
if ((op = x) == EXTENDED_ARG) continue;
|
|
|
|
arg = a;
|
2021-09-05 08:20:03 +00:00
|
|
|
switch (op) {
|
|
|
|
case SETUP_EXCEPT:
|
|
|
|
istry = true;
|
|
|
|
break;
|
|
|
|
case POP_BLOCK:
|
|
|
|
istry = false;
|
|
|
|
break;
|
|
|
|
case LOAD_CONST:
|
2021-10-02 13:17:17 +00:00
|
|
|
if ((item = PyTuple_GetItem(co_consts, arg))) {
|
|
|
|
if (PyLong_Check(item)) {
|
|
|
|
if ((rel = PyLong_AsLong(item)) == -1) {
|
|
|
|
if (PyErr_Occurred()) {
|
|
|
|
PyErr_Clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = -1;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IMPORT_NAME:
|
2021-10-02 13:17:17 +00:00
|
|
|
if (((item = PyTuple_GetItem(co_names, arg)) &&
|
|
|
|
(name = PyUnicode_AsUTF8String(item)))) {
|
|
|
|
free(mod);
|
|
|
|
if (*PyBytes_AS_STRING(name)) {
|
|
|
|
if (rel) {
|
|
|
|
mod = GetModSibling(PyBytes_AS_STRING(name), rel);
|
2021-09-13 04:04:44 +00:00
|
|
|
} else {
|
2021-10-02 13:17:17 +00:00
|
|
|
mod = xstrdup(PyBytes_AS_STRING(name));
|
|
|
|
}
|
|
|
|
if (!IsIgnoredModule(mod)) {
|
|
|
|
if (istry) {
|
|
|
|
Yoink(mod);
|
|
|
|
} else {
|
|
|
|
Forcepull(mod);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (IsDot()) {
|
|
|
|
if (rel) {
|
|
|
|
mod = GetModSibling(0, rel);
|
|
|
|
} else {
|
|
|
|
mod = GetParent();
|
2021-09-13 04:04:44 +00:00
|
|
|
}
|
2021-09-07 02:24:10 +00:00
|
|
|
} else {
|
2021-10-02 13:17:17 +00:00
|
|
|
mod = 0;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
2021-10-02 13:17:17 +00:00
|
|
|
Py_DECREF(name);
|
2021-09-07 02:24:10 +00:00
|
|
|
} else {
|
2021-10-02 13:17:17 +00:00
|
|
|
rc = -1;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-09-07 02:24:10 +00:00
|
|
|
case IMPORT_FROM:
|
2021-10-02 13:17:17 +00:00
|
|
|
if (((item = PyTuple_GetItem(co_names, arg)) &&
|
|
|
|
(name = PyUnicode_AsUTF8String(item)))) {
|
|
|
|
if (mod) {
|
|
|
|
imp = xstrcat(mod, '.', PyBytes_AS_STRING(name));
|
2021-09-13 04:04:44 +00:00
|
|
|
} else {
|
2021-10-02 13:17:17 +00:00
|
|
|
imp = xstrdup(PyBytes_AS_STRING(name));
|
2021-09-13 04:04:44 +00:00
|
|
|
}
|
2021-10-02 13:17:17 +00:00
|
|
|
if (!IsIgnoredModule(imp)) {
|
|
|
|
if (istry) {
|
|
|
|
Yoink(imp);
|
|
|
|
} else {
|
|
|
|
Forcepull(imp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_DECREF(name);
|
|
|
|
free(imp);
|
|
|
|
} else {
|
|
|
|
rc = -1;
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case STORE_NAME:
|
|
|
|
case STORE_GLOBAL:
|
|
|
|
if (globals) {
|
2021-10-02 13:17:17 +00:00
|
|
|
if (((item = PyTuple_GetItem(co_names, arg)) &&
|
|
|
|
(name = PyUnicode_AsUTF8String(item)))) {
|
|
|
|
intern(globals, PyBytes_AS_STRING(name));
|
|
|
|
Py_DECREF(name);
|
|
|
|
} else {
|
|
|
|
rc = -1;
|
|
|
|
}
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
|
|
|
break;
|
2021-09-05 08:20:03 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-09-07 02:24:10 +00:00
|
|
|
a = 0;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
2021-09-07 02:24:10 +00:00
|
|
|
free(mod);
|
2021-10-02 13:17:17 +00:00
|
|
|
if (!rc) {
|
|
|
|
if ((iter = PyObject_GetIter(co_consts))) {
|
|
|
|
while (!rc && (item = PyIter_Next(iter))) {
|
|
|
|
if (PyCode_Check(item)) {
|
|
|
|
rc |= Analyze(modname, item, 0);
|
|
|
|
}
|
|
|
|
Py_DECREF(item);
|
|
|
|
}
|
|
|
|
Py_DECREF(iter);
|
|
|
|
if (!rc && PyErr_Occurred()) {
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = -1;
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-02 13:17:17 +00:00
|
|
|
return rc;
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
|
|
|
|
2021-10-02 13:17:17 +00:00
|
|
|
static int
|
2021-09-07 02:24:10 +00:00
|
|
|
AnalyzeModule(const char *modname)
|
|
|
|
{
|
2021-10-02 13:17:17 +00:00
|
|
|
int rc;
|
2021-09-07 02:24:10 +00:00
|
|
|
char *p;
|
|
|
|
struct Interner *globals;
|
|
|
|
globals = newinterner();
|
|
|
|
intern(globals, "__file__");
|
2021-10-02 13:17:17 +00:00
|
|
|
if (!(rc = Analyze(modname, code, globals))) {
|
|
|
|
for (p = globals->p; *p; p += strlen(p) + 1) {
|
|
|
|
Provide(modname, p);
|
|
|
|
}
|
2021-09-07 02:24:10 +00:00
|
|
|
}
|
|
|
|
freeinterner(globals);
|
2021-10-02 13:17:17 +00:00
|
|
|
return rc;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
Objectify(void)
|
2021-09-04 22:44:00 +00:00
|
|
|
{
|
2021-10-02 13:17:17 +00:00
|
|
|
int rc;
|
2021-09-04 22:44:00 +00:00
|
|
|
bool ispkg;
|
2021-09-13 04:04:44 +00:00
|
|
|
size_t i, n;
|
2021-09-05 08:20:03 +00:00
|
|
|
char header[12];
|
|
|
|
size_t pysize, pycsize, marsize;
|
|
|
|
char *pydata, *pycdata, *mardata, *zipfile, *zipdir, *synfile, *modname;
|
2021-09-04 22:44:00 +00:00
|
|
|
zipdir = gc(GetZipDir());
|
|
|
|
zipfile = gc(GetZipFile());
|
|
|
|
synfile = gc(GetSynFile());
|
|
|
|
modname = gc(GetModName(&ispkg));
|
2021-09-05 08:20:03 +00:00
|
|
|
CHECK_NOTNULL((pydata = gc(xslurp(pyfile, &pysize))));
|
2021-09-07 02:24:10 +00:00
|
|
|
if ((!(code = Py_CompileStringExFlags(pydata, synfile, Py_file_input,
|
2021-09-05 08:20:03 +00:00
|
|
|
NULL, optimize)) ||
|
|
|
|
!(marsh = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION)))) {
|
2021-10-02 13:17:17 +00:00
|
|
|
return -1;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
|
|
|
assert(PyBytes_CheckExact(marsh));
|
|
|
|
mardata = PyBytes_AS_STRING(marsh);
|
|
|
|
marsize = PyBytes_GET_SIZE(marsh);
|
2022-05-13 12:05:12 +00:00
|
|
|
WRITE16LE(header+0, 3390); /* Python 3.7a1 */
|
2021-09-05 08:20:03 +00:00
|
|
|
WRITE16LE(header+2, READ16LE("\r\n"));
|
|
|
|
WRITE32LE(header+4, timestamp.tv_sec);
|
|
|
|
WRITE32LE(header+8, marsize);
|
|
|
|
pycsize = sizeof(header) + marsize;
|
|
|
|
pycdata = gc(malloc(pycsize));
|
|
|
|
memcpy(pycdata, header, sizeof(header));
|
|
|
|
memcpy(pycdata + sizeof(header), mardata, marsize);
|
2021-09-07 02:24:10 +00:00
|
|
|
yoinked = newinterner();
|
2021-09-13 04:04:44 +00:00
|
|
|
forcepulls = newinterner();
|
2021-09-04 22:44:00 +00:00
|
|
|
elf = elfwriter_open(outpath, 0644);
|
|
|
|
elfwriter_cargoculting(elf);
|
|
|
|
if (ispkg) {
|
|
|
|
elfwriter_zip(elf, zipdir, zipdir, strlen(zipdir),
|
2021-09-28 05:58:51 +00:00
|
|
|
pydata, 0, 040755, timestamp, timestamp,
|
2023-06-10 16:15:19 +00:00
|
|
|
timestamp, nocompress);
|
2021-09-04 22:44:00 +00:00
|
|
|
}
|
|
|
|
if (!binonly) {
|
|
|
|
elfwriter_zip(elf, gc(xstrcat("py:", modname)), zipfile,
|
|
|
|
strlen(zipfile), pydata, pysize, st.st_mode, timestamp,
|
2023-06-10 16:15:19 +00:00
|
|
|
timestamp, timestamp, nocompress);
|
2021-09-04 22:44:00 +00:00
|
|
|
}
|
|
|
|
elfwriter_zip(elf, gc(xstrcat("pyc:", modname)), gc(xstrcat(zipfile, 'c')),
|
|
|
|
strlen(zipfile) + 1, pycdata, pycsize, st.st_mode, timestamp,
|
2023-06-10 16:15:19 +00:00
|
|
|
timestamp, timestamp, nocompress);
|
2021-09-05 08:20:03 +00:00
|
|
|
elfwriter_align(elf, 1, 0);
|
2023-06-10 16:15:19 +00:00
|
|
|
elfwriter_startsection(elf, ".yoink", SHT_PROGBITS, 0);
|
2021-10-02 13:17:17 +00:00
|
|
|
if (!(rc = AnalyzeModule(modname))) {
|
|
|
|
if (*path_prefix && !IsDot()) {
|
|
|
|
elfwriter_yoink(elf, gc(xstrcat(path_prefix, "/")), STB_GLOBAL);
|
|
|
|
}
|
|
|
|
if (strchr(modname, '.')) {
|
|
|
|
Forcepull(gc(GetParent2()));
|
|
|
|
}
|
|
|
|
for (i = 0; i < yoinks.n; ++i) {
|
|
|
|
elfwriter_yoink(elf, yoinks.p[i], STB_GLOBAL);
|
|
|
|
}
|
|
|
|
if (insertrunner) {
|
|
|
|
elfwriter_yoink(elf, "RunPythonModule", STB_GLOBAL);
|
|
|
|
} else if (insertlauncher) {
|
|
|
|
elfwriter_yoink(elf, "LaunchPythonModule", STB_GLOBAL);
|
|
|
|
}
|
2021-09-12 05:30:37 +00:00
|
|
|
elfwriter_finishsection(elf);
|
2021-10-02 13:17:17 +00:00
|
|
|
if (insertrunner || insertlauncher) {
|
|
|
|
n = strlen(modname) + 1;
|
|
|
|
elfwriter_align(elf, 1, 0);
|
|
|
|
elfwriter_startsection(elf, ".rodata.str1.1", SHT_PROGBITS,
|
|
|
|
SHF_ALLOC | SHF_MERGE | SHF_STRINGS);
|
|
|
|
memcpy(elfwriter_reserve(elf, n), modname, n);
|
|
|
|
elfwriter_appendsym(elf, "kLaunchPythonModuleName",
|
|
|
|
ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
|
|
|
STV_DEFAULT, 0, n);
|
|
|
|
elfwriter_commit(elf, n);
|
|
|
|
elfwriter_finishsection(elf);
|
|
|
|
}
|
2021-09-12 05:30:37 +00:00
|
|
|
}
|
2021-09-04 22:44:00 +00:00
|
|
|
elfwriter_close(elf);
|
2021-09-13 04:04:44 +00:00
|
|
|
freeinterner(forcepulls);
|
2021-09-07 02:24:10 +00:00
|
|
|
freeinterner(yoinked);
|
2021-10-02 13:17:17 +00:00
|
|
|
return rc;
|
2021-09-05 08:20:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
2021-10-02 13:17:17 +00:00
|
|
|
int ec;
|
2023-06-09 06:44:03 +00:00
|
|
|
ShowCrashReports();
|
2022-03-16 23:59:45 +00:00
|
|
|
timestamp.tv_sec = 1647414000; /* determinism */
|
|
|
|
/* clock_gettime(CLOCK_REALTIME, ×tamp); */
|
2021-09-05 08:20:03 +00:00
|
|
|
GetOpts(argc, argv);
|
|
|
|
Py_NoUserSiteDirectory++;
|
|
|
|
Py_NoSiteFlag++;
|
|
|
|
Py_IgnoreEnvironmentFlag++;
|
|
|
|
Py_FrozenFlag++;
|
|
|
|
_Py_InitializeEx_Private(1, 0);
|
2021-10-02 13:17:17 +00:00
|
|
|
if (!Objectify()) {
|
|
|
|
ec = 0;
|
|
|
|
} else {
|
|
|
|
PyErr_Print();
|
|
|
|
ec = 1;
|
|
|
|
}
|
2021-09-05 08:20:03 +00:00
|
|
|
Py_XDECREF(marsh);
|
2021-09-13 04:04:44 +00:00
|
|
|
Py_XDECREF(code);
|
2021-10-02 13:17:17 +00:00
|
|
|
if (Py_FinalizeEx() < 0 && !ec) ec = 120;
|
|
|
|
return ec;
|
2021-09-04 22:44:00 +00:00
|
|
|
}
|