diff --git a/.gitignore b/.gitignore index d459afdde..62fa0d429 100644 --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,9 @@ tests/benchmarks/bin/* compile_commands.json src/openvic-simulation/testing/test_results/results.txt +# Out-of-source build directory +build/ + # ccls .ccls-cache diff --git a/SConstruct b/SConstruct index 11bbcd6d1..7efb885dc 100644 --- a/SConstruct +++ b/SConstruct @@ -25,42 +25,68 @@ opts.Add(BoolVariable("build_ovsim_headless", "Build the openvic simulation head env.FinalizeOptions() +suffix = ".{}.{}".format(env["platform"], env["target"]) +if env.dev_build: + suffix += ".dev" +if env["precision"] == "double": + suffix += ".double" +suffix += "." + env["arch"] +if env["platform"] == "windows": + if env.get("debug_crt", False): + suffix += ".mdd" + elif env.get("use_static_cpp", False): + suffix += ".mt" + else: + suffix += ".md" +if env.get("use_asan", False): + suffix += ".san" +env["suffix"] = suffix + +build_dir = env.Dir("build/" + suffix.lstrip(".")).abspath.replace("\\", "/") +env["build_dir"] = build_dir + env.exposed_includes = [] SConscript("deps/SCsub", "env") env.openvic_simulation = {} -Default( - env.CommandNoCache( - "src/openvic-simulation/gen/commit_info.gen.hpp", - env.Value(env.get_git_info()), - env.Run(env.git_builder), - name_prefix="sim", - ) +# Tweak this if you want to use different folders, or more folders, to store your source code in. +source_path = "src/openvic-simulation" +include_path = "src" +# Mirror the simulation source tree into the per-config build dir +sim_variant = build_dir + "/" + source_path # forward slashes so VariantDir matches +sim_variant_parent = build_dir + "/" + include_path # variant of "src/" +env.VariantDir(sim_variant, source_path, duplicate=True) + +env.Append(CPPPATH=[[env.Dir(p) for p in [sim_variant, sim_variant_parent]]]) + +gen_commit_info = env.CommandNoCache( + sim_variant + "/gen/commit_info.gen.hpp", + env.Value(env.get_git_info()), + env.Run(env.git_builder), + name_prefix="sim", ) -Default( - env.CommandNoCache( - "src/openvic-simulation/gen/license_info.gen.hpp", - ["#COPYRIGHT", "#LICENSE.md"], - env.Run(env.license_builder), - name_prefix="sim", - ) +gen_license_info = env.CommandNoCache( + sim_variant + "/gen/license_info.gen.hpp", + ["#COPYRIGHT", "#LICENSE.md"], + env.Run(env.license_builder), + name_prefix="sim", ) -Default( - env.CommandNoCache( - "src/openvic-simulation/gen/author_info.gen.hpp", - "#AUTHORS.md", - env.Run(env.author_builder), - name_prefix="sim", - sections={ - "Senior Developers": "AUTHORS_SENIOR_DEVELOPERS", - "Developers": "AUTHORS_DEVELOPERS", - "Contributors": "AUTHORS_CONTRIBUTORS", - "Consultants": "AUTHORS_CONSULTANTS", - }, - ) +gen_author_info = env.CommandNoCache( + sim_variant + "/gen/author_info.gen.hpp", + "#AUTHORS.md", + env.Run(env.author_builder), + name_prefix="sim", + sections={ + "Senior Developers": "AUTHORS_SENIOR_DEVELOPERS", + "Developers": "AUTHORS_DEVELOPERS", + "Contributors": "AUTHORS_CONTRIBUTORS", + "Consultants": "AUTHORS_CONSULTANTS", + }, ) +gen_files = gen_commit_info + gen_license_info + gen_author_info +Default(gen_commit_info, gen_license_info, gen_author_info) # For future reference: # - CCFLAGS are compilation flags shared between C and C++ @@ -70,27 +96,25 @@ Default( # - CPPDEFINES are for pre-processor defines # - LINKFLAGS are for linking flags -# Tweak this if you want to use different folders, or more folders, to store your source code in. -source_path = "src/openvic-simulation" -include_path = "src" -env.Append(CPPPATH=[[env.Dir(p) for p in [source_path, include_path]]]) -sources = env.GlobRecursive("*.cpp", [source_path]) +# Exclude pch.cpp from the regular source list so it isn't compiled twice +# (env.PCH below builds it once with /Yc). +pch_cpp_variant = sim_variant + "/pch.cpp" +sources = env.GlobRecursive("*.cpp", [sim_variant], pch_cpp_variant) env.simulation_sources = sources -suffix = ".{}.{}".format(env["platform"], env["target"]) -if env.dev_build: - suffix += ".dev" -if env["precision"] == "double": - suffix += ".double" -suffix += "." + env["arch"] - -# Expose it when included from another project -env["suffix"] = suffix - library = None env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"] library_name = "libopenvic-simulation{}{}".format(suffix, env["LIBSUFFIX"]) +# Precompiled header +if env.get("is_msvc", False): + pch_header_rel = "openvic-simulation/pch.hpp" + env["PCHSTOP"] = pch_header_rel + pch_pch, pch_obj = env.PCH(pch_cpp_variant) + env["PCH"] = pch_pch + env.Append(CCFLAGS=["/FI" + pch_header_rel]) + sources.append(pch_obj) + default_args = [] if env["run_ovsim_tests"]: @@ -106,12 +130,17 @@ if env["build_ovsim_library"]: library = env.StaticLibrary(target=env.File(os.path.join(BINDIR, library_name)), source=sources) default_args += [library] + # VariantDir(..., duplicate=True) copies sources into build_dir but does + # not register the copies as targets, so `scons -c` leaves them behind. + env.Clean(library, env.Dir(build_dir)) + env.Append(LIBPATH=[env.Dir(BINDIR)]) env.Prepend(LIBS=[library_name]) env.openvic_simulation["LIBPATH"] = env["LIBPATH"] env.openvic_simulation["LIBS"] = env["LIBS"] - env.openvic_simulation["INCPATH"] = [env.Dir(include_path)] + env.exposed_includes + env.openvic_simulation["INCPATH"] = [env.Dir(sim_variant_parent)] + env.exposed_includes + env.openvic_simulation["GEN_FILES"] = gen_files headless_program = None env["PROGSUFFIX"] = suffix + env["PROGSUFFIX"] @@ -119,10 +148,12 @@ env["PROGSUFFIX"] = suffix + env["PROGSUFFIX"] if env["build_ovsim_headless"]: headless_name = "openvic-simulation" headless_env = env.Clone() - headless_path = ["src/headless"] + headless_src = "src/headless" + headless_variant = build_dir + "/" + headless_src + headless_env.VariantDir(headless_variant, headless_src, duplicate=True) headless_env.Append(CPPDEFINES=["OPENVIC_SIM_HEADLESS"]) - headless_env.Append(CPPPATH=[headless_env.Dir(headless_path)]) - headless_env.headless_sources = env.GlobRecursive("*.cpp", headless_path) + headless_env.Append(CPPPATH=[headless_env.Dir(headless_variant)]) + headless_env.headless_sources = env.GlobRecursive("*.cpp", [headless_variant]) if not env["build_ovsim_library"]: headless_env.headless_sources += sources headless_program = headless_env.Program( @@ -132,6 +163,10 @@ if env["build_ovsim_headless"]: ) default_args += [headless_program] + # Also wipe the per-config build dir when the headless target is cleaned, + # in case the library target isn't built in this configuration. + headless_env.Clean(headless_program, headless_env.Dir(build_dir)) + if env["build_ovsim_tests"]: tests_env = SConscript("tests/SCsub", "env") diff --git a/deps/SCsub b/deps/SCsub index 80b14f616..96993acfa 100644 --- a/deps/SCsub +++ b/deps/SCsub @@ -55,7 +55,6 @@ def build_std_function(env): def build_memory(env): - import os from pathlib import Path import methods @@ -113,18 +112,22 @@ def build_memory(env): CXXFLAGS=["-pedantic-errors", "-Werror", "-Wall", "-Wextra", "-Wconversion", "-Wsign-conversion"] ) memory_env.Append(CPPPATH=[[memory_env.Dir(p) for p in [source_path, Path(inner_include_path)]]]) - sources = env.GlobRecursive("*.cpp", [source_path]) + # Mirror memory's source tree into the per-config build dir + build_root = (env.get("build_dir") or env.Dir("#").abspath).replace("\\", "/") + out_dir = build_root + "/memory/" + source_path + memory_env.VariantDir(out_dir, source_path, duplicate=True) + sources = env.GlobRecursive("*.cpp", [out_dir]) env.memory_sources = sources - library_name = "libmemory" + env["LIBSUFFIX"] - library = memory_env.StaticLibrary(target=os.path.join(source_path, library_name), source=sources) + library_name = "libmemory" + env.get("suffix", "") + env["LIBSUFFIX"] + library = memory_env.StaticLibrary(target=out_dir + "/" + library_name, source=sources) Default([config, node_size_impl, library]) env.memory = {} env.memory["INCPATH"] = [memory_env.Dir(include_path)] env.Append(CPPPATH=env.memory["INCPATH"]) - env.Append(LIBPATH=[memory_env.Dir(source_path)]) + env.Append(LIBPATH=[memory_env.Dir(out_dir)]) env.Prepend(LIBS=[library_name]) env.exposed_includes += env.memory["INCPATH"] @@ -174,11 +177,15 @@ def build_spdlog(env): env.spdlog["INCPATH"] = [spdlog_env.Dir(include_path)] spdlog_env.Append(CPPPATH=[source_dir, env.spdlog["INCPATH"]]) - sources = env.GlobRecursive("*.cpp", [source_path]) + # Mirror spdlog's source tree into the per-config build dir. + build_root = (env.get("build_dir") or env.Dir("#").abspath).replace("\\", "/") + spdlog_out = build_root + "/spdlog/" + source_path + spdlog_env.VariantDir(spdlog_out, source_path, duplicate=True) + sources = env.GlobRecursive("*.cpp", [spdlog_out]) env.spdlog_sources = sources - library_name = "libspdlog" + env["LIBSUFFIX"] - library = spdlog_env.StaticLibrary(target=os.path.join(source_path, library_name), source=sources) + library_name = "libspdlog" + env.get("suffix", "") + env["LIBSUFFIX"] + library = spdlog_env.StaticLibrary(target=spdlog_out + "/" + library_name, source=sources) Default(library) env.Append(CPPPATH=[env.spdlog["INCPATH"]]) @@ -186,7 +193,7 @@ def build_spdlog(env): env.Append(CXXFLAGS=[f"/external:I{env.spdlog['INCPATH'][0]}"]) else: env.Append(CXXFLAGS=["-isystem", env.spdlog["INCPATH"][0]]) - env.Append(LIBPATH=[source_dir]) + env.Append(LIBPATH=[spdlog_env.Dir(spdlog_out)]) env.Prepend(LIBS=[library_name]) env.exposed_includes += env.spdlog["INCPATH"] diff --git a/deps/lexy-vdf b/deps/lexy-vdf index 35a3d93c3..b241a1708 160000 --- a/deps/lexy-vdf +++ b/deps/lexy-vdf @@ -1 +1 @@ -Subproject commit 35a3d93c35a21953e6948debef02acd1c0083a06 +Subproject commit b241a1708be097b0f511021f3b6f5d8ea382250a diff --git a/deps/openvic-dataloader b/deps/openvic-dataloader index 083938fcc..9b37b6acd 160000 --- a/deps/openvic-dataloader +++ b/deps/openvic-dataloader @@ -1 +1 @@ -Subproject commit 083938fcc25374c57e78978f6377272974bebfa8 +Subproject commit 9b37b6acdd0686cc58c269ef3b087c50cf6b635d diff --git a/scripts b/scripts index 4ddc9a1b9..d8f908cb2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4ddc9a1b9b14fddab397325a1d016de56d465d75 +Subproject commit d8f908cb2d7b4a4564d12f71cbfe97bed241195f diff --git a/src/openvic-simulation/pch.cpp b/src/openvic-simulation/pch.cpp new file mode 100644 index 000000000..680811844 --- /dev/null +++ b/src/openvic-simulation/pch.cpp @@ -0,0 +1 @@ +#include "openvic-simulation/pch.hpp" diff --git a/src/openvic-simulation/pch.hpp b/src/openvic-simulation/pch.hpp new file mode 100644 index 000000000..ed588dd1c --- /dev/null +++ b/src/openvic-simulation/pch.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include diff --git a/tests/SCsub b/tests/SCsub index af7f28482..c885eae89 100644 --- a/tests/SCsub +++ b/tests/SCsub @@ -40,13 +40,16 @@ env.openvic_simulation_tests = {} # - LINKFLAGS are for linking flags # tweak this if you want to use different folders, or more folders, to store your source code in. -source_path = "src" +source_path = "src" # relative to this SCsub (i.e. tests/src under the sim root) tests_name = "openvic-simulation" tests_env = env.Clone() +# Mirror tests/src into the per-config build dir +tests_variant = env["build_dir"] + "/tests/" + source_path +tests_env.VariantDir(tests_variant, source_path, duplicate=True) tests_env.Append(CPPDEFINES=["OPENVIC_SIMULATION_TESTS"]) -tests_env.Append(CPPPATH=[tests_env.Dir(source_path)]) -tests_env.tests_sources = env.GlobRecursive("*.cpp", [source_path]) +tests_env.Append(CPPPATH=[tests_env.Dir(tests_variant)]) +tests_env.tests_sources = env.GlobRecursive("*.cpp", [tests_variant]) SConscript("deps/SCsub", {"env": tests_env}) diff --git a/tests/benchmarks/SCsub b/tests/benchmarks/SCsub index 814718e12..4ccb97985 100644 --- a/tests/benchmarks/SCsub +++ b/tests/benchmarks/SCsub @@ -40,13 +40,17 @@ env.openvic_simulation_benchmarks = {} # - LINKFLAGS are for linking flags # tweak this if you want to use different folders, or more folders, to store your source code in. -source_path = "src" +source_path = "src" # relative to this SCsub (i.e. tests/benchmarks/src under the sim root) benchmarks_name = "openvic-simulation" benchmarks_env = env.Clone() +# Mirror benchmarks/src into the per-config build dir +benchmarks_variant = env["build_dir"] + "/tests/benchmarks/" + source_path +benchmarks_env.VariantDir(benchmarks_variant, source_path, duplicate=True) benchmarks_env.Append(CPPDEFINES=["OPENVIC_SIMULATION_BENCHMARKS"]) -benchmarks_env.Append(CPPPATH=[benchmarks_env.Dir(source_path)]) -benchmarks_env.benchmarks_sources = env.GlobRecursive("*.cpp", [source_path]) + +benchmarks_env.Append(CPPPATH=[benchmarks_env.Dir(benchmarks_variant)]) +benchmarks_env.benchmarks_sources = env.GlobRecursive("*.cpp", [benchmarks_variant]) SConscript("deps/SCsub", {"env": benchmarks_env, "parent_env": env}) diff --git a/tests/deps/SCsub b/tests/deps/SCsub index c12679007..67f2797da 100644 --- a/tests/deps/SCsub +++ b/tests/deps/SCsub @@ -177,27 +177,31 @@ def build_snitch(env): ) snitch_env.Append(CPPPATH=[[snitch_env.Dir(p) for p in [source_path, include_path]]]) - sources = snitch_env.GlobRecursive("*.cpp", [source_path], Path(source_path) / unity_source) + # Mirror snitch's source tree into the per-config build dir + build_root = (env.get("build_dir") or env.Dir("#").abspath).replace("\\", "/") + snitch_out = build_root + "/snitch/" + source_path + snitch_env.VariantDir(snitch_out, source_path, duplicate=True) + sources = snitch_env.GlobRecursive("*.cpp", [snitch_out], snitch_out + "/" + unity_source) if UNITY_BUILD: - sources = [snitch_env.File(Path(source_path) / unity_source)] + sources = [snitch_env.File(snitch_out + "/" + unity_source)] env.snitch_sources = sources if not HEADER_ONLY: library = None project_name = "snitch" - library_name = "lib" + project_name + env["LIBSUFFIX"] + library_name = "lib" + project_name + env.get("suffix", "") + env["LIBSUFFIX"] if SHARED_BUILD: if snitch_env.get("is_msvc", False): pass else: snitch_env.Append(CXXFLAGS=["-fvisibility=hidden", "-fvisibility-inlines-hidden"]) - library = snitch_env.SharedLibrary(target=Path(source_path) / library_name, source=sources) + library = snitch_env.SharedLibrary(target=snitch_out + "/" + library_name, source=sources) else: - library = snitch_env.StaticLibrary(target=Path(source_path) / library_name, source=sources) - env.Append(LIBPATH=[snitch_env.Dir(source_path)]) + library = snitch_env.StaticLibrary(target=snitch_out + "/" + library_name, source=sources) + env.Append(LIBPATH=[snitch_env.Dir(snitch_out)]) env.Prepend(LIBS=[library_name]) Default([config, library])