Prove that Makefile is fully defined

The whole repository is now buildable with GNU Make Landlock sandboxing.
This proves that no Makefile targets exist which touch files other than
their declared prerequisites. In order to do this, we had to:

  1. Stop code morphing GCC output in package.com and instead run a
     newly introduced FIXUPOBJ.COM command after GCC invocations.

  2. Disable all the crumby Python unit tests that do things like create
     files in the current directory, or rename() files between folders.
     This ended up being a lot of tests, but most of them are still ok.

  3. Introduce an .UNSANDBOXED variable to GNU Make to disable Landlock.
     We currently only do this for things like `make tags`.

  4. This change deletes some GNU Make code that was preventing the
     execve() optimization from working. This means it should no longer
     be necessary in most cases for command invocations to be indirected
     through the cocmd interpreter.

  5. Missing dependencies had to be declared in certain places, in cases
     where they couldn't be automatically determined by MKDEPS.COM

  6. The libcxx header situation has finally been tamed. One of the
     things that makes this difficult is MKDEPS.COM only wants to
     consider the first 64kb of a file, in order to go fast. But libcxx
     likes to have #include lines buried after huge documentation.

  7. An .UNVEIL variable has been introduced to GNU Make just in case
     we ever wish to explicitly specify additional things that need to
     be whitelisted which aren't strictly prerequisites. This works in
     a manner similar to the recently introduced .EXTRA_PREREQS feature.

There's now a new build/bootstrap/make.com prebuilt binary available. It
should no longer be possible to write invalid Makefile code.
This commit is contained in:
Justine Tunney 2022-08-06 03:51:50 -07:00
parent acdf591833
commit cf93ecbbb2
181 changed files with 1902 additions and 1986 deletions

View file

@ -3,10 +3,18 @@
PKGS += TOOL_BUILD_EMUCRT
TOOL_BUILD_EMUCRT = \
o/$(MODE)/tool/build/emucrt/emucrt.o \
TOOL_BUILD_EMUCRT = \
o/$(MODE)/tool/build/emucrt/emucrt.o \
o/$(MODE)/tool/build/emucrt/emucrt.lds
o/$(MODE)/tool/build/emucrt/emucrt.o: \
tool/build/emucrt/emucrt.S \
libc/macros.internal.h \
libc/macros-cpp.internal.inc \
libc/intrin/asancodes.h \
ape/relocations.h \
libc/macros.internal.inc
.PHONY: o/$(MODE)/tool/build/emucrt
o/$(MODE)/tool/build/emucrt: \
o/$(MODE)/tool/build/emucrt: \
$(TOOL_BUILD_EMUCRT)

188
tool/build/fixupobj.c Normal file
View file

@ -0,0 +1,188 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/elf/elf.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/rela.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/fmt/itoa.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "third_party/getopt/getopt.h"
/**
* @fileoverview GCC Codegen Fixer-Upper.
*/
#define GETOPTS "h"
#define USAGE \
"\
Usage: fixupobj.com [-h] ARGS...\n\
-?\n\
-h show help\n\
"
void Write(const char *s, ...) {
va_list va;
va_start(va, s);
do {
write(2, s, strlen(s));
} while ((s = va_arg(va, const char *)));
va_end(va);
}
wontreturn void SysExit(int rc, const char *call, const char *thing) {
int err;
char ibuf[12];
const char *estr;
err = errno;
FormatInt32(ibuf, err);
estr = strerdoc(err);
if (!estr) estr = "EUNKNOWN";
Write(thing, ": ", call, "() failed: ", estr, " (", ibuf, ")\n", 0);
exit(rc);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
switch (opt) {
case 'h':
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
default:
write(2, USAGE, sizeof(USAGE) - 1);
exit(64);
}
}
}
void OptimizeRelocations(Elf64_Ehdr *elf, size_t elfsize) {
char *strs;
Elf64_Half i;
struct Op *op;
Elf64_Sym *syms;
Elf64_Rela *rela;
Elf64_Xword symcount;
unsigned char *code, *p;
Elf64_Shdr *shdr, *shdrcode;
CHECK_NOTNULL((strs = GetElfStringTable(elf, elfsize)));
CHECK_NOTNULL((syms = GetElfSymbolTable(elf, elfsize, &symcount)));
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, elfsize, i);
if (shdr->sh_type == SHT_RELA) {
CHECK_EQ(sizeof(struct Elf64_Rela), shdr->sh_entsize);
CHECK_NOTNULL(
(shdrcode = GetElfSectionHeaderAddress(elf, elfsize, shdr->sh_info)));
if (!(shdrcode->sh_flags & SHF_EXECINSTR)) continue;
CHECK_NOTNULL((code = GetElfSectionAddress(elf, elfsize, shdrcode)));
for (rela = GetElfSectionAddress(elf, elfsize, shdr);
((uintptr_t)rela + shdr->sh_entsize <=
min((uintptr_t)elf + elfsize,
(uintptr_t)elf + shdr->sh_offset + shdr->sh_size));
++rela) {
/*
* GCC isn't capable of -mnop-mcount when using -fpie.
* Let's fix that. It saves ~14 cycles per function call.
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
*/
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
strcmp(GetElfString(elf, elfsize, strs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
p = code + rela->r_offset - 2;
p[0] = 0x66; /* nopw 0x00(%rax,%rax,1) */
p[1] = 0x0f;
p[2] = 0x1f;
p[3] = 0x44;
p[4] = 0x00;
p[5] = 0x00;
}
/*
* Let's just try to nop mcount calls in general due to the above.
*/
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
strcmp(GetElfString(elf, elfsize, strs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
p = code + rela->r_offset - 1;
p[0] = 0x0f; /* nopl 0x00(%rax,%rax,1) */
p[1] = 0x1f;
p[2] = 0x44;
p[3] = 0x00;
p[4] = 0x00;
}
}
}
}
}
void RewriteObject(const char *path) {
int fd;
struct stat st;
Elf64_Ehdr *elf;
if ((fd = open(path, O_RDWR)) == -1) {
SysExit(__COUNTER__ + 1, "open", path);
}
if (fstat(fd, &st) == -1) {
SysExit(__COUNTER__ + 1, "fstat", path);
}
if (st.st_size >= 64) {
if ((elf = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
0)) == MAP_FAILED) {
SysExit(__COUNTER__ + 1, "mmap", path);
}
OptimizeRelocations(elf, st.st_size);
if (msync(elf, st.st_size, MS_ASYNC | MS_INVALIDATE)) {
SysExit(__COUNTER__ + 1, "msync", path);
}
if (munmap(elf, st.st_size)) {
SysExit(__COUNTER__ + 1, "munmap", path);
}
}
if (close(fd)) {
SysExit(__COUNTER__ + 1, "close", path);
}
}
int main(int argc, char *argv[]) {
int i, opt;
if (IsModeDbg()) ShowCrashReports();
GetOpts(argc, argv);
for (i = optind; i < argc; ++i) {
RewriteObject(argv[i]);
}
}

View file

@ -94,6 +94,10 @@ o/$(MODE)/tool/build/lib/apetest2.com.zip.o: \
ZIPOBJ_FLAGS += \
-B
o/$(MODE)/tool/build/lib/apetest.o: \
tool/build/lib/apetest.c \
libc/calls/calls.h
TOOL_BUILD_LIB_LIBS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)))
TOOL_BUILD_LIB_SRCS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_SRCS))
TOOL_BUILD_LIB_HDRS = $(foreach x,$(TOOL_BUILD_LIB_ARTIFACTS),$($(x)_HDRS))

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_TOOL_BUILD_LIB_FDS_H_
#include "libc/calls/struct/iovec.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_

View file

@ -352,9 +352,6 @@ bool IsObjectSource(const char *name) {
for (i = 0; i < ARRAYLEN(kSourceExts); ++i) {
if (endswith(name, kSourceExts[i])) return true;
}
if (strstr(name, "/libcxx/")) {
return true;
}
return false;
}

View file

@ -18,41 +18,23 @@
*/
#include "libc/alg/alg.h"
#include "libc/alg/arraylist.internal.h"
#include "libc/alg/bisect.internal.h"
#include "libc/alg/bisectcarleft.internal.h"
#include "libc/assert.h"
#include "libc/bits/bswap.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/elf/struct/rela.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/kompressor.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/getopt/getopt.h"
#include "third_party/xed/x86.h"
#include "third_party/zlib/zlib.h"
#include "tool/build/lib/elfwriter.h"
#include "tool/build/lib/getargs.h"
#include "tool/build/lib/persist.h"
@ -82,33 +64,6 @@
* These rules help keep the structure of large codebases easy to
* understand. More importantly, it allows us to further optimize
* compiled objects very cheaply as the build progresses.
*
* SECOND PURPOSE
*
* Compress read-only data sections of particularly low entropy, using
* the most appropriate directly-linked algorithm and then inject code
* into _init() that calls it. If the data is extremely low energy, we
* will inject code for merging page table entries too. The overcommit
* here is limitless.
*
* POSSIBLE PURPOSE
*
* It might be nice to have all storage to be thread-local storage. So
* we change RIP-relative instructions to be RBX-relative, only when
* they reference sections in the binary mutable after initialization.
*
* This is basically what the Go language does to implement its fiber
* multiprocessing model. We can have this in C by appropriating all the
* work folks put into enriching GNU C with WIN32 and ASLR lool.
*
* CAVEATS
*
* This tool monkey patches `.o` files as a side-effect since we're not
* able to modify the GCC source code. Therefore it's VERY IMPORTANT to
* have Makefile rules which build `.a` or `.com.dbg` *depend* upon the
* `.pkg` rule. That way they happen in the right order. Otherwise they
* might build binaries with compromised profiling nops at the start of
* functions, which will almost certainly result in SIGILL.
*/
#define PACKAGE_MAGIC bswap_32(0xBEEFBEEFu)
@ -149,15 +104,6 @@ struct Packages {
kPiroBss,
kBss,
} kind;
struct Ops {
size_t i, n;
struct Op {
int32_t offset;
uint8_t length;
uint8_t pos_disp;
uint16_t __pad;
} * p;
} ops;
} * p;
} sections; // not persisted
} * p; // persisted as pkg+RVA
@ -273,7 +219,6 @@ void GetOpts(struct Package *pkg, struct Packages *deps, int argc,
void IndexSections(struct Object *obj) {
size_t i;
struct Op op;
const char *name;
const uint8_t *code;
struct Section sect;
@ -306,23 +251,6 @@ void IndexSections(struct Object *obj) {
} else {
sect.kind = kUndef; /* should always and only be section #0 */
}
if (shdr->sh_flags & SHF_EXECINSTR) {
CHECK_NOTNULL((code = GetElfSectionAddress(obj->elf, obj->size, shdr)));
for (op.offset = 0; op.offset < shdr->sh_size; op.offset += op.length) {
if (xed_instruction_length_decode(
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64),
&code[op.offset],
min(shdr->sh_size - op.offset, XED_MAX_INSTRUCTION_BYTES)) ==
XED_ERROR_NONE) {
op.length = xedd.length;
op.pos_disp = xedd.op.pos_disp;
} else {
op.length = 1;
op.pos_disp = 0;
}
CHECK_NE(-1, append(&sect.ops, &op));
}
}
CHECK_NE(-1, append(&obj->sections, &sect));
}
}
@ -384,9 +312,6 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot,
}
void CloseObject(struct Object *obj) {
if ((obj->mode & O_ACCMODE) != O_RDONLY) {
CHECK_NE(-1, msync(obj->elf, obj->size, MS_ASYNC | MS_INVALIDATE));
}
CHECK_NE(-1, munmap(obj->elf, obj->size));
}
@ -475,214 +400,22 @@ forceinline uint8_t ChangeRipToRbx(uint8_t modrm) {
return (modrm & 0b00111000) | 0b10000011;
}
void OptimizeRelocations(struct Package *pkg, struct Packages *deps,
struct Object *obj) {
Elf64_Half i;
struct Op *op;
Elf64_Rela *rela;
struct Symbol *refsym;
struct Package *refpkg;
unsigned char *code, *p;
Elf64_Shdr *shdr, *shdrcode;
for (i = 0; i < obj->elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i);
if (shdr->sh_type == SHT_RELA) {
CHECK_EQ(sizeof(struct Elf64_Rela), shdr->sh_entsize);
CHECK_NOTNULL((shdrcode = GetElfSectionHeaderAddress(obj->elf, obj->size,
shdr->sh_info)));
if (!(shdrcode->sh_flags & SHF_EXECINSTR)) continue;
CHECK_NOTNULL(
(code = GetElfSectionAddress(obj->elf, obj->size, shdrcode)));
for (rela = GetElfSectionAddress(obj->elf, obj->size, shdr);
((uintptr_t)rela + shdr->sh_entsize <=
min((uintptr_t)obj->elf + obj->size,
(uintptr_t)obj->elf + shdr->sh_offset + shdr->sh_size));
++rela) {
CHECK_LT(ELF64_R_SYM(rela->r_info), obj->symcount);
#if 0
/*
* Change (%rip) to (%rbx) on program instructions that
* reference memory, if and only if the memory location is a
* global variable that's mutable after initialization. The
* displacement is also updated to be relative to the image
* base, rather than relative to the program counter.
*/
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCREL) &&
FindSymbol(
GetElfString(obj->elf, obj->size, obj->strs,
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
pkg, deps, &refpkg, &refsym) &&
(refsym->kind == kData || refsym->kind == kBss) &&
IsRipRelativeModrm(code[rela->r_offset - 1])) {
op = &obj->sections.p[shdr->sh_info].ops.p[bisectcarleft(
(const int32_t(*)[2])obj->sections.p[shdr->sh_info].ops.p,
obj->sections.p[shdr->sh_info].ops.i, rela->r_offset)];
CHECK_GT(op->length, 4);
CHECK_GT(op->pos_disp, 0);
rela->r_info = ELF64_R_INFO(ELF64_R_SYM(rela->r_info), R_X86_64_32S);
rela->r_addend = -IMAGE_BASE_VIRTUAL + rela->r_addend +
(op->length - op->pos_disp);
code[rela->r_offset - 1] = ChangeRipToRbx(code[rela->r_offset - 1]);
}
#endif
/*
* GCC isn't capable of -mnop-mcount when using -fpie.
* Let's fix that. It saves ~14 cycles per function call.
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
*/
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
strcmp(GetElfString(obj->elf, obj->size, obj->strs,
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
p = &code[rela->r_offset - 2];
p[0] = 0x66; /* nopw 0x00(%rax,%rax,1) */
p[1] = 0x0f;
p[2] = 0x1f;
p[3] = 0x44;
p[4] = 0x00;
p[5] = 0x00;
}
/*
* Let's just try to nop mcount calls in general due to the above.
*/
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
strcmp(GetElfString(obj->elf, obj->size, obj->strs,
obj->syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
p = &code[rela->r_offset - 1];
p[0] = 0x0f; /* nopl 0x00(%rax,%rax,1) */
p[1] = 0x1f;
p[2] = 0x44;
p[3] = 0x00;
p[4] = 0x00;
}
}
}
}
}
bool IsSymbolDirectlyReachable(struct Package *pkg, struct Packages *deps,
const char *symbol) {
return FindSymbol(symbol, pkg, deps, NULL, NULL);
}
struct RlEncoder {
size_t i, n;
struct RlDecode *p;
};
ssize_t rlencode_extend(struct RlEncoder *rle, size_t n) {
size_t n2;
struct RlDecode *p2;
n2 = rle->n;
if (!n2) n2 = 512;
while (n > n2) n2 += n2 >> 1;
if (!(p2 = realloc(rle->p, n2 * sizeof(rle->p[0])))) return -1;
rle->p = p2;
rle->n = n2;
return n2;
}
void rlencode_encode(struct RlEncoder *rle, const unsigned char *data,
size_t size) {
size_t i, j;
for (i = 0; i < size; i += j) {
for (j = 1; j < 255 && i + j < size; ++j) {
if (data[i] != data[i + j]) break;
}
rle->p[rle->i].repititions = j;
rle->p[rle->i].byte = data[i];
rle->i++;
}
rle->p[rle->i].repititions = 0;
rle->p[rle->i].byte = 0;
rle->i++;
}
ssize_t rlencode(struct RlEncoder *rle, const unsigned char *data,
size_t size) {
if (size + 1 > rle->n && rlencode_extend(rle, size + 1) == -1) return -1;
rlencode_encode(rle, data, size);
assert(rle->i <= rle->n);
return rle->i;
}
void CompressLowEntropyReadOnlyDataSections(struct Package *pkg,
struct Packages *deps,
struct Object *obj) {
Elf64_Half i;
const char *name;
unsigned char *p;
Elf64_Shdr *shdr;
struct RlEncoder rle;
bool haverldecode, isprofitable;
bzero(&rle, sizeof(rle));
haverldecode = IsSymbolDirectlyReachable(pkg, deps, "rldecode");
for (i = 0; i < obj->elf->e_shnum; ++i) {
if ((shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i)) &&
shdr->sh_size >= 256 &&
(shdr->sh_type == SHT_PROGBITS &&
!(shdr->sh_flags &
(SHF_WRITE | SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED))) &&
(p = GetElfSectionAddress(obj->elf, obj->size, shdr)) &&
startswith((name = GetElfSectionName(obj->elf, obj->size, shdr)),
".rodata") &&
rlencode(&rle, p, shdr->sh_size) != -1) {
isprofitable = rle.i * sizeof(rle.p[0]) <= shdr->sh_size / 2;
INFOF("%s(%s): rlencode()%s on %s is%s profitable (%,zu → %,zu bytes)",
&pkg->strings.p[pkg->path], &pkg->strings.p[obj->path],
haverldecode ? "" : " [NOT LINKED]", name,
isprofitable ? "" : " NOT", shdr->sh_size,
rle.i * sizeof(rle.p[0]));
}
}
free(rle.p);
}
void RewriteObjects(struct Package *pkg, struct Packages *deps) {
size_t i;
struct Object *obj;
#if 0
struct ElfWriter *elf;
elf = elfwriter_open(gc(xstrcat(&pkg->strings.p[pkg->path], ".o")), 0644);
elfwriter_cargoculting(elf);
#endif
for (i = 0; i < pkg->objects.i; ++i) {
obj = &pkg->objects.p[i];
OpenObject(pkg, obj, O_RDWR, PROT_READ | PROT_WRITE, MAP_SHARED);
OptimizeRelocations(pkg, deps, obj);
#if 0
CompressLowEntropyReadOnlyDataSections(pkg, deps, obj);
#endif
CloseObject(obj);
}
#if 0
elfwriter_close(elf);
#endif
}
void Package(int argc, char *argv[], struct Package *pkg,
struct Packages *deps) {
size_t i, j;
GetOpts(pkg, deps, argc, argv);
LoadObjects(pkg);
CheckStrictDeps(pkg, deps);
RewriteObjects(pkg, deps);
WritePackage(pkg);
for (i = 0; i < deps->i; ++i) {
CHECK_NE(-1, munmap(deps->p[i]->addr, deps->p[i]->size));
}
for (i = 0; i < pkg->objects.i; ++i) {
for (j = 0; j < pkg->objects.p[i].sections.i; ++j) {
free(pkg->objects.p[i].sections.p[j].ops.p);
}
free(pkg->objects.p[i].sections.p);
}
free(pkg->strings.p);

View file

@ -102,6 +102,7 @@ void Visit(const char *path) {
if (endswith(path, "/internal.h")) return;
if (endswith(path, ".internal.inc")) return;
if (endswith(path, "/internal.inc")) return;
if (startswith(path, "libc/isystem/")) return;
isheader = endswith(path, ".h");
if (isheader && isinterned(visited, path)) return;
appends(&output, "\n\f\n/*!BEGIN ");

View file

@ -30,6 +30,8 @@
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"

View file

@ -189,7 +189,7 @@
(runs (format "o/$m/%s.com%s V=5 TESTARGS=-b" name runsuffix))
(buns (format "o/$m/test/%s_test.com%s V=5 TESTARGS=-b" name runsuffix)))
(cond ((not (member ext '("c" "cc" "s" "S" "rl" "f")))
(format "m=%s; make -j12 -O MODE=$m o/$m/%s"
(format "m=%s; o//third_party/make/make.com -j12 -O MODE=$m o/$m/%s"
mode
(directory-file-name
(or (file-name-directory
@ -200,7 +200,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 -O $f MODE=$m")
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
"scp $f $f.dbg win7:"
"ssh win7 ./%s.com"))
mode name (file-name-nondirectory name)))
@ -209,7 +209,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 -O $f MODE=$m")
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
"scp $f $f.dbg win10:"
"ssh win10 ./%s.com"))
mode name (file-name-nondirectory name)))
@ -218,19 +218,19 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 -O $f MODE=$m")
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
"scp $f $f.dbg xnu:"
"ssh xnu ./%s.com"))
mode name (file-name-nondirectory name)))
((and (equal suffix "")
(cosmo-contains "_test." (buffer-file-name)))
(format "m=%s; make -j12 -O MODE=$m %s"
(format "m=%s; o//third_party/make/make.com -j12 -O MODE=$m %s"
mode runs))
((and (equal suffix "")
(file-exists-p (format "%s" buddy)))
(format (cosmo-join
" && "
'("m=%s; n=%s; make -j12 -O o/$m/$n%s.o MODE=$m"
'("m=%s; n=%s; o//third_party/make/make.com -j12 -O o/$m/$n%s.o MODE=$m"
;; "bloat o/$m/%s.o | head"
;; "nm -C --size o/$m/%s.o | sort -r"
"echo"
@ -242,11 +242,11 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 -O $f MODE=$m")
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
"./$f"))
mode name))
((eq kind 'test)
(format `"m=%s; f=o/$m/%s.com.ok && make -j12 -O $f MODE=$m" mode name))
(format `"m=%s; f=o/$m/%s.com.ok && o//third_party/make/make.com -j12 -O $f MODE=$m" mode name))
((and (file-regular-p this)
(file-executable-p this))
(format "./%s" file))
@ -255,7 +255,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s%s.o"
,(concat "make -j12 -O $f MODE=$m")
,(concat "o//third_party/make/make.com -j12 -O $f MODE=$m")
;; "nm -C --size $f | sort -r"
"echo"
"size -A $f | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2"
@ -465,7 +465,7 @@
(error "don't know how to show assembly for non c/c++ source file"))
(let* ((default-directory root)
(compile-command
(format "make %s -j12 -O MODE=%s %s %s"
(format "o//third_party/make/make.com %s -j12 -O MODE=%s %s %s"
(or extra-make-flags "") mode asm-gcc asm-clang)))
(save-buffer)
(set-visited-file-modtime (current-time))
@ -612,7 +612,7 @@
(cond ((save-excursion
(goto-char (point-min))
(looking-at "#!"))
(compile (format "sh %s" file)))
(compile (format "sh -c %s" file)))
((file-executable-p file)
(compile (if (cosmo-contains "/" file)
file
@ -622,15 +622,15 @@
(compile-command (cosmo--compile-command this root 'run mode "" "" ".runs")))
(compile compile-command)))
((eq major-mode 'sh-mode)
(compile (format "sh %s" file)))
(compile (format "sh -c %s" file)))
((eq major-mode 'lua-mode)
(let* ((mode (cosmo--make-mode arg))
(redbean ))
(compile (format "make -j16 MODE=%s o/%s/tool/net/redbean.com && o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
(compile (format "o//third_party/make/make.com -j16 MODE=%s o/%s/tool/net/redbean.com && o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
((and (eq major-mode 'python-mode)
(cosmo-startswith "third_party/python/Lib/test/" file))
(let ((mode (cosmo--make-mode arg)))
(compile (format "make -j12 MODE=%s PYHARNESSARGS=-vv PYTESTARGS=-v o/%s/%s.py.runs"
(compile (format "o//third_party/make/make.com -j12 MODE=%s PYHARNESSARGS=-vv PYTESTARGS=-v o/%s/%s.py.runs"
mode mode (file-name-sans-extension file)))))
((eq major-mode 'python-mode)
(compile (format "python.com %s" file)))

View file

@ -23,6 +23,7 @@
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"

View file

@ -60,6 +60,7 @@
#include "libc/runtime/stack.h"
#include "libc/sock/goodsocket.internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/append.internal.h"
#include "libc/stdio/hex.internal.h"
#include "libc/stdio/stdio.h"

20
tool/scripts/check-includes.py Executable file
View file

@ -0,0 +1,20 @@
#!/usr/bin/env python.com
import os
import sys
def CheckFile(path):
if path.endswith(('.png', '.ico')):
return
sys.stderr.write('%s\n' % (path))
with open(path) as f:
data = f.read()
assert '#include' not in data[65530:], "late include in %s" % (path)
for arg in sys.argv[1:]:
if os.path.isdir(arg):
for dirpath, dirs, files in os.walk(arg):
for filepath in files:
CheckFile(os.path.join(dirpath, filepath))
else:
CheckFile(arg)

28
tool/scripts/get-deps.py Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env python.com
import os
import re
import sys
def GetDeps(path):
sys.stdout.write('o/$(MODE)/%s.o:' % (os.path.splitext(path)[0]))
deps = set()
def Dive(path):
if path in deps:
return
deps.add(path)
sys.stdout.write(' \\\n\t\t%s' % (path))
with open(path) as f:
code = f.read()
for dep in re.findall(r'[.#]include "([^"]+)"', code):
Dive(dep)
Dive(path)
sys.stdout.write('\n')
for arg in sys.argv[1:]:
if os.path.isdir(arg):
for dirpath, dirs, files in os.walk(arg):
for filepath in files:
GetDeps(os.path.join(dirpath, filepath))
else:
GetDeps(arg)

View file

@ -69,6 +69,7 @@
#include "libc/rand/rand.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"

View file

@ -37,6 +37,7 @@
#include "libc/nexgen32e/bsf.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"

View file

@ -60,6 +60,7 @@
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/pollfd.h"
#include "libc/stdio/internal.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"