mirror of https://github.com/ludocode/mpack
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
617 lines
22 KiB
Python
617 lines
22 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# Copyright (c) 2015-2021 Nicholas Fraser and the MPack authors
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
# this software and associated documentation files (the "Software"), to deal in
|
|
# the Software without restriction, including without limitation the rights to
|
|
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
# subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
# This is the buildsystem configuration tool for the MPack unit test suite. It
|
|
# tests the compiler for support for various flags and features and generates a
|
|
# ninja build file to build the unit test suite in a variety of configurations.
|
|
#
|
|
# It can be run with a GCC-style compiler or with MSVC. To run it with MSVC,
|
|
# you must first have the Visual Studio build tools on your path. This means
|
|
# you need to either open a Visual Studio Build Tools command prompt, or source
|
|
# vsvarsall.bat for some version of the Visual Studio Build Tools.
|
|
|
|
import shutil, os, sys, subprocess
|
|
from os import path
|
|
|
|
globalbuild = path.join(".build", "unit")
|
|
os.makedirs(globalbuild, exist_ok=True)
|
|
|
|
|
|
|
|
###################################################
|
|
# Determine Compiler
|
|
###################################################
|
|
|
|
cc = None
|
|
compiler = "unknown"
|
|
|
|
if os.getenv("CC"):
|
|
cc = os.getenv("CC")
|
|
elif shutil.which("cl.exe"):
|
|
cc = "cl"
|
|
else:
|
|
cc = "cc"
|
|
|
|
if not shutil.which(cc):
|
|
raise Exception("Compiler cannot be found!")
|
|
|
|
if cc.lower() == "cl" or cc.lower() == "cl.exe":
|
|
compiler = "MSVC"
|
|
elif cc.endswith("cproc"):
|
|
compiler = "cproc"
|
|
elif cc.endswith("chibicc"):
|
|
compiler = "chibicc"
|
|
elif cc.endswith("8cc"):
|
|
compiler = "8cc"
|
|
else:
|
|
# try --version
|
|
ret = subprocess.run([cc, "--version"], universal_newlines=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
if ret.returncode == 0:
|
|
if ret.stdout.startswith("cparser "):
|
|
compiler = "cparser"
|
|
elif "clang" in ret.stdout:
|
|
compiler = "Clang"
|
|
|
|
if compiler == "unknown":
|
|
# try -v
|
|
ret = subprocess.run([cc, "-v"], universal_newlines=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
if ret.returncode == 0:
|
|
for line in (ret.stdout + "\n" + ret.stderr).splitlines():
|
|
if line.startswith("tcc "):
|
|
compiler = "TinyCC"
|
|
break
|
|
elif line.startswith("gcc "):
|
|
compiler = "GCC"
|
|
break
|
|
|
|
print("Using " + compiler + " compiler with executable: " + cc)
|
|
|
|
if compiler == "MSVC":
|
|
obj_extension = ".obj"
|
|
exe_extension = ".exe"
|
|
else:
|
|
obj_extension = ".o"
|
|
exe_extension = ""
|
|
|
|
msvc = (compiler == "MSVC")
|
|
|
|
|
|
|
|
###################################################
|
|
# Compiler Probing
|
|
###################################################
|
|
|
|
config = {
|
|
"flags": {},
|
|
}
|
|
|
|
flagtest_src = path.join(globalbuild, "flagtest.c")
|
|
flagtest_exe = path.join(globalbuild, "flagtest" + exe_extension)
|
|
with open(flagtest_src, "w") as out:
|
|
out.write("""
|
|
int main(int argc, char** argv) {
|
|
// array dereference to test for the existence of
|
|
// sanitizer libs when using -fsanitize (libubsan)
|
|
// compare it to another string in the array so that
|
|
// -Wzero-as-null-pointer-constant works
|
|
return argv[argc - 1] == argv[0];
|
|
}
|
|
""")
|
|
|
|
def checkFlags(flags):
|
|
if isinstance(flags, str):
|
|
flags = [flags,]
|
|
|
|
configArg = "|".join(flags)
|
|
if configArg in config["flags"]:
|
|
return config["flags"][configArg]
|
|
print("Testing flag(s): " + " ".join(flags) + " ... ", end="")
|
|
sys.stdout.flush()
|
|
|
|
if msvc:
|
|
cmd = [cc, "/WX"] + flags + [flagtest_src, "/Fe" + flagtest_exe]
|
|
else:
|
|
cmd = [cc, "-Werror"] + flags + [flagtest_src, "-o", flagtest_exe]
|
|
ret = subprocess.run(cmd, universal_newlines=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
|
|
if ret.returncode == 0:
|
|
print("Supported.")
|
|
supported = True
|
|
else:
|
|
print("Not supported.")
|
|
supported = False
|
|
config["flags"][configArg] = supported
|
|
return supported
|
|
|
|
def flagsIfSupported(flags):
|
|
if checkFlags(flags):
|
|
if isinstance(flags, str):
|
|
return [flags]
|
|
return flags
|
|
return []
|
|
|
|
# We use -Og for all debug builds if we have it, but ONLY under GCC. It can
|
|
# sometimes improve warnings, and things run a lot faster especially under
|
|
# Valgrind, but Clang stupidly maps it to -O1 which has some optimizations
|
|
# that break debugging!
|
|
hasOg = False
|
|
print("Testing flag(s): -Og ... ", end="")
|
|
sys.stdout.flush()
|
|
if msvc:
|
|
print("Not supported.")
|
|
else:
|
|
ret = subprocess.run([cc, "-v"], universal_newlines=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
sys.stdout.flush()
|
|
if ret.returncode != 0:
|
|
print("Not supported.")
|
|
else:
|
|
for line in ret.stdout.splitlines():
|
|
if line.startswith("gcc version"):
|
|
hasOg = True
|
|
break
|
|
if hasOg:
|
|
print("Supported.")
|
|
else:
|
|
print("May be supported, but we won't use it.")
|
|
|
|
|
|
|
|
###################################################
|
|
# Common Flags
|
|
###################################################
|
|
|
|
global_cppflags = []
|
|
|
|
if msvc:
|
|
global_cppflags += [
|
|
"/W4", "/WX",
|
|
# debug to PDB with synchronous writes since we're doing parallel builds
|
|
# (we specify a per-build PDB path during build generation below)
|
|
"/Zi", "/FS"
|
|
]
|
|
else:
|
|
global_cppflags += [
|
|
"-Wall", "-Wextra", "-Werror",
|
|
"-Wconversion", "-Wundef",
|
|
"-Wshadow", "-Wcast-qual",
|
|
"-g",
|
|
]
|
|
|
|
global_cppflags += [
|
|
"-Isrc", "-Itest/unit/src",
|
|
"-DMPACK_VARIANT_BUILDS=1",
|
|
"-DMPACK_HAS_CONFIG=1",
|
|
]
|
|
|
|
defaultfeatures = [
|
|
"-DMPACK_READER=1",
|
|
"-DMPACK_WRITER=1",
|
|
"-DMPACK_EXPECT=1",
|
|
"-DMPACK_NODE=1",
|
|
]
|
|
|
|
allfeatures = defaultfeatures + [
|
|
"-DMPACK_COMPATIBILITY=1",
|
|
"-DMPACK_EXTENSIONS=1",
|
|
]
|
|
|
|
noioconfigs = [
|
|
"-DMPACK_STDLIB=1",
|
|
"-DMPACK_MALLOC=test_malloc",
|
|
"-DMPACK_FREE=test_free",
|
|
]
|
|
|
|
allconfigs = noioconfigs + [
|
|
"-DMPACK_STDIO=1",
|
|
]
|
|
|
|
# optimization
|
|
if msvc:
|
|
debugflags = ["/Od", "/MDd"]
|
|
releaseflags = ["/O2", "/MD"]
|
|
else:
|
|
debugflags = [hasOg and "-Og" or "-O0"]
|
|
releaseflags = ["-O2"]
|
|
debugflags.append("-DDEBUG")
|
|
releaseflags.append("-DNDEBUG")
|
|
|
|
# flags for specifying source language
|
|
cxxlinkflags = []
|
|
if msvc:
|
|
cflags = ["/TC"]
|
|
cxxflags = ["/TP", "/EHsc"]
|
|
else:
|
|
cflags = [
|
|
checkFlags("-std=c11") and "-std=c11" or "-std=c99",
|
|
"-Wc++-compat"
|
|
]
|
|
cxxflags = [
|
|
"-x", "c++",
|
|
"-Wmissing-declarations",
|
|
]
|
|
# When building as C++ on macOS, clang will emit calls to std::terminate
|
|
# even if no C++ features are used so libc++ is required. We link with cc,
|
|
# not c++ so we need to link it manually, and there is apparently no way to
|
|
# link it statically either. (This overrides the use of libstdc++ if libc++
|
|
# is installed so it's not ideal. We can worry about this later.)
|
|
if checkFlags(cxxflags + ["-lc++"]):
|
|
cxxlinkflags.append("-lc++")
|
|
|
|
|
|
|
|
###################################################
|
|
# Variable Flags
|
|
###################################################
|
|
|
|
if not os.getenv("CI") and not msvc:
|
|
# we have to force color diagnostics to get color output from ninja
|
|
# (ninja will strip the colors if it's being piped)
|
|
if checkFlags("-fdiagnostics-color=always"):
|
|
global_cppflags.append("-fdiagnostics-color=always")
|
|
elif checkFlags("-fcolor-diagnostics=always"):
|
|
global_cppflags.append("-color-diagnostics=always")
|
|
|
|
if checkFlags("-Wstrict-aliasing=3"):
|
|
global_cppflags.append("-Wstrict-aliasing=3")
|
|
elif checkFlags("-Wstrict-aliasing=2"):
|
|
global_cppflags.append("-Wstrict-aliasing=2")
|
|
elif checkFlags("-Wstrict-aliasing"):
|
|
global_cppflags.append("-Wstrict-aliasing")
|
|
|
|
extra_warnings_to_test = [
|
|
"-Wpedantic",
|
|
"-Wmissing-variable-declarations",
|
|
"-Wfloat-conversion",
|
|
]
|
|
if not msvc:
|
|
extra_warnings_to_test += ["-fstrict-aliasing"]
|
|
|
|
for flag in extra_warnings_to_test:
|
|
global_cppflags += flagsIfSupported(flag)
|
|
|
|
cflags += flagsIfSupported("-Wmissing-prototypes")
|
|
cflags += flagsIfSupported("-Wstrict-prototypes")
|
|
|
|
#TODO
|
|
ltoflags = []
|
|
|
|
|
|
|
|
###################################################
|
|
# Build configuration
|
|
###################################################
|
|
|
|
builds = {}
|
|
|
|
class Build:
|
|
def __init__(self, name, cppflags, ldflags):
|
|
self.name = name
|
|
self.cppflags = cppflags
|
|
self.ldflags = ldflags
|
|
self.run_wrapper = None
|
|
self.exclude = False
|
|
|
|
def addBuild(name, cppflags, ldflags=[]):
|
|
builds[name] = Build(name, cppflags[:], ldflags[:])
|
|
|
|
def addDebugReleaseBuilds(name, cppflags, ldflags = []):
|
|
addBuild(name + "-debug", cppflags + debugflags, ldflags)
|
|
addBuild(name + "-release", cppflags + releaseflags, ldflags)
|
|
|
|
addDebugReleaseBuilds('default', defaultfeatures + allconfigs + cflags)
|
|
addDebugReleaseBuilds('everything', allfeatures + allconfigs + cflags)
|
|
addDebugReleaseBuilds('empty', allconfigs + cflags)
|
|
addDebugReleaseBuilds('reader', ["-DMPACK_READER=1"] + allconfigs + cflags)
|
|
addDebugReleaseBuilds('expect', ["-DMPACK_READER=1", "-DMPACK_EXPECT=1"] + allconfigs + cflags)
|
|
addDebugReleaseBuilds('node', ["-DMPACK_NODE=1"] + allconfigs + cflags)
|
|
addDebugReleaseBuilds('compatibility', defaultfeatures + ["-DMPACK_COMPATIBILITY=1"] + allconfigs + cflags)
|
|
addDebugReleaseBuilds('extensions', defaultfeatures + ["-DMPACK_EXTENSIONS=1"] + allconfigs + cflags)
|
|
addDebugReleaseBuilds('no-float', allfeatures + allconfigs + cflags + ["-DMPACK_FLOAT=0"])
|
|
addDebugReleaseBuilds('no-double', allfeatures + allconfigs + cflags + ["-DMPACK_DOUBLE=0"])
|
|
|
|
# writer builds
|
|
addDebugReleaseBuilds('writer-only',
|
|
["-DMPACK_WRITER=1", "-DMPACK_BUILDER=0"]
|
|
+ allconfigs + cflags)
|
|
addDebugReleaseBuilds('builder-internal',
|
|
["-DMPACK_WRITER=1", "-DMPACK_BUILDER=1", "-DMPACK_BUILDER_INTERNAL_STORAGE=1"]
|
|
+ allconfigs + cflags)
|
|
addDebugReleaseBuilds('builder-nointernal',
|
|
["-DMPACK_WRITER=1", "-DMPACK_BUILDER=1", "-DMPACK_BUILDER_INTERNAL_STORAGE=0"]
|
|
+ allconfigs + cflags)
|
|
|
|
# no i/o
|
|
addDebugReleaseBuilds('noio', allfeatures + noioconfigs + cflags)
|
|
addDebugReleaseBuilds('noio-writer', ["-DMPACK_WRITER=1"] + noioconfigs + cflags)
|
|
addDebugReleaseBuilds('noio-reader', ["-DMPACK_READER=1"] + noioconfigs + cflags)
|
|
addDebugReleaseBuilds('noio-expect', ["-DMPACK_READER=1", "-DMPACK_EXPECT=1"] + noioconfigs + cflags)
|
|
addDebugReleaseBuilds('noio-node', ["-DMPACK_NODE=1"] + noioconfigs + cflags)
|
|
|
|
# embedded builds without libc (using builtins)
|
|
addDebugReleaseBuilds('embed', allfeatures + cflags)
|
|
addDebugReleaseBuilds('embed-writer', ["-DMPACK_WRITER=1"] + cflags)
|
|
addDebugReleaseBuilds('embed-reader', ["-DMPACK_READER=1"] + cflags)
|
|
addDebugReleaseBuilds('embed-expect', ["-DMPACK_READER=1", "-DMPACK_EXPECT=1"] + cflags)
|
|
addDebugReleaseBuilds('embed-node', ["-DMPACK_NODE=1"] + cflags)
|
|
addDebugReleaseBuilds('embed-nobuiltins', ["-DMPACK_NO_BUILTINS=1"] + allfeatures + cflags)
|
|
|
|
haveValgrind = shutil.which("valgrind")
|
|
|
|
if haveValgrind:
|
|
# use valgrind for everything build if available
|
|
builds["everything-debug"].run_wrapper = "valgrind"
|
|
builds["everything-release"].run_wrapper = "valgrind"
|
|
|
|
# language versions
|
|
if msvc:
|
|
addDebugReleaseBuilds('c++', allfeatures + allconfigs + cxxflags)
|
|
elif compiler != "TinyCC":
|
|
|
|
# MPack is really C11 code with C++ support. We need lots of compiler
|
|
# extensions to build as ANSI C. We technically only support gnu89 so we
|
|
# need to disable pedantic C89 warnings. We add
|
|
# -Wdeclaration-after-statement even though MPack mixes declarations and
|
|
# code just to make sure MPack disables the warning properly.
|
|
gnu89flags = ["-std=gnu89", "-Wno-pedantic", "-Wdeclaration-after-statement"]
|
|
if checkFlags(gnu89flags):
|
|
addDebugReleaseBuilds('gnu89', allfeatures + allconfigs + gnu89flags)
|
|
|
|
if checkFlags("-std=c11"):
|
|
# if we're using c11 for everything else, we still need to test c99
|
|
addDebugReleaseBuilds('c99', allfeatures + allconfigs + ["-std=c99"])
|
|
|
|
for version in ["c++11", "gnu++11", "c++14", "c++17"]:
|
|
flags = cxxflags + ["-std=" + version]
|
|
if checkFlags(flags):
|
|
addDebugReleaseBuilds(version, allfeatures + allconfigs + flags, cxxlinkflags)
|
|
|
|
# Make sure C++11 compiles with disabled features (see #66)
|
|
cxx11flags = cxxflags + ["-std=c++11"]
|
|
if checkFlags(cxx11flags):
|
|
addDebugReleaseBuilds('c++11-empty', allconfigs + cxx11flags, cxxlinkflags)
|
|
|
|
# We disable pedantic in C++98 due to our use of variadic macros, trailing
|
|
# commas, ll format specifiers, and probably more. We technically only support
|
|
# C++98 with those extensions.
|
|
cxx98flags = cxxflags + ["-std=c++98"]
|
|
if checkFlags("-Wno-pedantic"):
|
|
cxx98flags += ["-Wno-pedantic"]
|
|
addDebugReleaseBuilds('c++98', allfeatures + allconfigs + cxx98flags, cxxlinkflags)
|
|
|
|
# 32-bit builds
|
|
if not msvc and checkFlags("-m32"):
|
|
addDebugReleaseBuilds('m32', allfeatures + allconfigs + cflags + ["-m32"], ["-m32"])
|
|
addDebugReleaseBuilds('cxx98-m32', allfeatures + allconfigs + cxx98flags + ["-m32"], ["-m32"])
|
|
if checkFlags(cxx11flags):
|
|
addDebugReleaseBuilds('c++11-m32', allfeatures + allconfigs + cxx11flags + ["-m32"], ["-m32"])
|
|
|
|
# lto build
|
|
if msvc:
|
|
addBuild('lto', allfeatures + allconfigs + cflags + releaseflags + ["/GL"], ["/LTCG"])
|
|
elif compiler != "TinyCC":
|
|
ltoflags = ["-O3", "-flto", "-fuse-linker-plugin", "-fno-fat-lto-objects"]
|
|
if checkFlags(ltoflags):
|
|
ltoflags = allfeatures + allconfigs + cflags + ltoflags
|
|
else:
|
|
ltoflags = ["-O3", "-flto"]
|
|
if checkFlags(ltoflags):
|
|
ltoflags = allfeatures + allconfigs + cflags + ltoflags
|
|
else:
|
|
ltoflags = None
|
|
if ltoflags:
|
|
addBuild('lto', ltoflags, ltoflags)
|
|
if haveValgrind:
|
|
builds["lto"].run_wrapper = "valgrind"
|
|
|
|
# size-optimized build (both debug and release)
|
|
if msvc:
|
|
sizeOptimize = ["/O1", "/MD"]
|
|
else:
|
|
sizeOptimize = ["-Os"]
|
|
addBuild('optimize-size-debug', allfeatures + allconfigs + cflags + sizeOptimize +
|
|
["-DMPACK_OPTIMIZE_FOR_SIZE=1", "-DMPACK_STRINGS=0", "-DDEBUG"])
|
|
addBuild('optimize-size-release', allfeatures + allconfigs + cflags + sizeOptimize +
|
|
["-DMPACK_OPTIMIZE_FOR_SIZE=1", "-DMPACK_STRINGS=0", "-DNDEBUG"])
|
|
|
|
# miscellaneous special builds
|
|
addBuild('notrack', allfeatures + allconfigs + cflags + debugflags + ["-DMPACK_NO_TRACKING=1"])
|
|
addDebugReleaseBuilds('realloc', allfeatures + allconfigs + cflags + ["-DMPACK_REALLOC=test_realloc"])
|
|
if not msvc and compiler != "TinyCC":
|
|
addBuild('O3', allfeatures + allconfigs + cflags + ["-O3"])
|
|
if haveValgrind:
|
|
builds["O3"].run_wrapper = "valgrind"
|
|
addBuild('fastmath', allfeatures + allconfigs + cflags + ["-ffast-math"])
|
|
if haveValgrind:
|
|
builds["fastmath"].run_wrapper = "valgrind"
|
|
addBuild('coverage', allfeatures + allconfigs + cflags +
|
|
["-DMPACK_GCOV=1", "--coverage", "-fno-inline", "-fno-inline-small-functions", "-fno-default-inline"],
|
|
["--coverage"])
|
|
builds["coverage"].exclude = True # don't run coverage during "all". run separately by CI.
|
|
if hasOg:
|
|
addBuild('O0', allfeatures + allconfigs + cflags + ["-DDEBUG", "-O0"])
|
|
|
|
# sanitizers
|
|
if msvc:
|
|
# https://devblogs.microsoft.com/cppblog/asan-for-windows-x64-and-debug-build-support/
|
|
# /INFERASANLIBS is enabled by default, no need to specify them anymore
|
|
addDebugReleaseBuilds('sanitize-address', allfeatures + allconfigs + cflags + ["/fsanitize=address"])
|
|
elif compiler != "TinyCC":
|
|
def addSanitizerBuilds(name, cppflags, ldflags=[]):
|
|
if checkFlags(cppflags):
|
|
addDebugReleaseBuilds(name, allfeatures + allconfigs + cflags + cppflags, ldflags)
|
|
addSanitizerBuilds('sanitize-undefined', ["-fsanitize=undefined"], ["-fsanitize=undefined"])
|
|
addSanitizerBuilds('sanitize-safe-stack', ["-fsanitize=safe-stack"], ["-fsanitize=safe-stack"])
|
|
addSanitizerBuilds('sanitize-address', ["-fsanitize=address"], ["-fsanitize=address"])
|
|
addSanitizerBuilds('sanitize-memory', ["-fsanitize=memory"], ["-fsanitize=memory"])
|
|
# not technically a sanitizer, but close enough:
|
|
addSanitizerBuilds('sanitize-stack-protector', ["-Wstack-protector", "-fstack-protector-all"])
|
|
|
|
|
|
|
|
###################################################
|
|
# Ninja generation
|
|
###################################################
|
|
|
|
srcs = []
|
|
|
|
for paths in [path.join("src", "mpack"), path.join("test", "unit", "src")]:
|
|
for root, dirs, files in os.walk(paths):
|
|
for name in files:
|
|
if name.endswith(".c"):
|
|
srcs.append(os.path.join(root, name))
|
|
|
|
ninja = path.join(globalbuild, "build.ninja")
|
|
with open(ninja, "w") as out:
|
|
out.write("# This file is auto-generated.\n")
|
|
out.write("# Do not edit it; your changes will be erased.\n")
|
|
out.write("\n")
|
|
|
|
# 1.3 for gcc deps, 1.1 for pool
|
|
out.write("ninja_required_version = 1.3\n")
|
|
out.write("\n")
|
|
|
|
out.write("rule compile\n")
|
|
if msvc:
|
|
out.write(" command = " + cc + " /showIncludes $flags /c $in /Fo$out\n")
|
|
out.write(" deps = msvc\n")
|
|
else:
|
|
out.write(" command = " + cc + " " + "-MD -MF $out.d $flags -c $in -o $out\n")
|
|
out.write(" deps = gcc\n")
|
|
out.write(" depfile = $out.d\n")
|
|
out.write("\n")
|
|
|
|
out.write("rule link\n")
|
|
if msvc:
|
|
out.write(" command = link $flags $in /OUT:$out\n")
|
|
else:
|
|
out.write(" command = " + cc + " $flags $in -o $out\n")
|
|
out.write("\n")
|
|
|
|
# unfortunately right now the unit tests all try to write to the same files,
|
|
# so they break when run concurrently. we need to make it write to files under
|
|
# that config's build/ folder; for now we just run them sequentially.
|
|
out.write("pool run_pool\n")
|
|
out.write(" depth = 1\n")
|
|
out.write("run_wrapper =\n")
|
|
out.write("rule run\n")
|
|
out.write(" command = $run_wrapper$in\n")
|
|
out.write(" pool = run_pool\n")
|
|
out.write("\n")
|
|
|
|
out.write("rule help\n")
|
|
out.write(" command = cat .build/help\n")
|
|
out.write("build help: help\n")
|
|
out.write("\n")
|
|
|
|
for buildname in sorted(builds.keys()):
|
|
build = builds[buildname]
|
|
buildfolder = path.join(globalbuild, buildname)
|
|
cppflags = global_cppflags + build.cppflags
|
|
ldflags = build.ldflags
|
|
objs = []
|
|
|
|
if msvc:
|
|
# Specify a per-build PDB path so that we don't try to link at the
|
|
# same time a PDB file is being written
|
|
cppflags.append("/Fd" + buildfolder)
|
|
ldflags.append("/DEBUG")
|
|
|
|
for src in srcs:
|
|
obj = path.join(buildfolder, "objs", src[:-2] + obj_extension)
|
|
objs.append(obj)
|
|
out.write("build " + obj + ": compile " + src + "\n")
|
|
out.write(" flags = " + " ".join(cppflags) + "\n")
|
|
|
|
runner = path.join(buildfolder, "runner") + exe_extension
|
|
|
|
out.write("build " + runner + ": link " + " ".join(objs) + "\n")
|
|
out.write(" flags = " + " ".join(ldflags) + "\n")
|
|
|
|
# You can omit "run-" in front of any build to just build it without
|
|
# running it. This lets you run it some other way (e.g. under gdb,
|
|
# with/without Valgrind, etc.)
|
|
out.write("build " + buildname + ": phony " + runner + "\n\n")
|
|
|
|
out.write("build run-" + buildname + ": run " + runner + "\n")
|
|
if build.run_wrapper:
|
|
run_wrapper = build.run_wrapper
|
|
out.write(" run_wrapper = " + run_wrapper + " ")
|
|
if run_wrapper == "valgrind":
|
|
out.write("--leak-check=full --error-exitcode=1 ")
|
|
out.write("--suppressions=tools/valgrind-suppressions ")
|
|
out.write("--show-leak-kinds=all --errors-for-leak-kinds=all ")
|
|
out.write("\n")
|
|
|
|
out.write("default run-everything-debug\n")
|
|
out.write("build default: phony run-everything-debug\n")
|
|
out.write("\n")
|
|
|
|
# Builds included under the "more" target
|
|
more = [
|
|
"run-default-debug",
|
|
"run-everything-debug",
|
|
"run-everything-release",
|
|
"run-embed-debug",
|
|
"run-embed-release",
|
|
"run-no-float-release",
|
|
]
|
|
if "gnu89-debug" in builds:
|
|
more += [
|
|
"run-gnu89-debug",
|
|
"run-gnu89-release",
|
|
]
|
|
if "c++11-debug" in builds:
|
|
more += [
|
|
"run-c++11-debug",
|
|
]
|
|
|
|
out.write("build more: phony " + " ".join(more))
|
|
if ltoflags:
|
|
out.write(" run-lto")
|
|
out.write("\n\n")
|
|
|
|
out.write("build all: phony")
|
|
for build in sorted(builds.keys()):
|
|
if not builds[build].exclude:
|
|
out.write(" run-")
|
|
out.write(build)
|
|
out.write("\n")
|
|
|
|
print("Generated " + ninja)
|
|
|
|
with open(path.join(globalbuild, "help"), "w") as out:
|
|
out.write("\n")
|
|
out.write("Available targets:\n")
|
|
out.write("\n")
|
|
out.write(" (default)\n")
|
|
out.write(" more\n")
|
|
out.write(" all\n")
|
|
out.write(" clean\n")
|
|
out.write(" help\n")
|
|
out.write("\n")
|
|
for build in sorted(builds.keys()):
|
|
out.write(" run-" + build + "\n")
|
|
out.close()
|