diff --git a/.github/workflows/linux_gcc_cmake_build.yml b/.github/workflows/linux_gcc_cmake_build.yml index 8a76b6dd..4770d4b7 100644 --- a/.github/workflows/linux_gcc_cmake_build.yml +++ b/.github/workflows/linux_gcc_cmake_build.yml @@ -63,6 +63,11 @@ jobs: run: | ctest --preset=${{env.BUILD_DEV_ALL_PRESET}} --parallel 2 + - name: Bootstrap through CMake + working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_ALL}} + run: | + cmake --build . --target run_buildcc_lib_bootstrap_linux_gcc + - name: Install working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_ALL}} run: | @@ -110,7 +115,7 @@ jobs: working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_ALL}} run: | cmake --build . --target run_hybrid_depchaining_example_linux - + - name: Hybrid Target Info Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_ALL}} run: | @@ -174,6 +179,11 @@ jobs: cat ../codecov.yml | curl --data-binary @- https://codecov.io/validate bash <(curl -s https://codecov.io/bash) -f coverage_truncated.info || echo "Codecov did not collect coverage reports" + - name: Bootstrap through CMake + working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_SINGLE}} + run: | + cmake --build . --target run_buildcc_lib_bootstrap_linux_gcc + - name: Install working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_DEV_SINGLE}} run: | diff --git a/.github/workflows/win_cmake_build.yml b/.github/workflows/win_cmake_build.yml index 9760177f..91e62ad8 100644 --- a/.github/workflows/win_cmake_build.yml +++ b/.github/workflows/win_cmake_build.yml @@ -50,6 +50,11 @@ jobs: cmake --build --list-presets cmake --build --preset=${{env.BUILD_MSVC_PRESET}} --config Release --parallel 2 + - name: Bootstrap through CMake + working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} + run: | + cmake --build . --config Release --target run_buildcc_lib_bootstrap_win_msvc --parallel 2 + - name: Install working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | @@ -68,42 +73,42 @@ jobs: - name: Hybrid Simple Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_simple_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_simple_example_win - name: Hybrid Foolib Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_foolib_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_foolib_example_win - name: Hybrid External Lib Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_externallib_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_externallib_example_win - name: Hybrid Custom Target Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_customtarget_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_customtarget_example_win - name: Hybrid Generic Target Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_generic_example + cmake --build . --config Release --parallel 2 --target run_hybrid_generic_example - name: Hybrid PCH Target Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_pch_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_pch_example_win - name: Hybrid Dep Chaining Target Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_depchaining_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_depchaining_example_win - name: Hybrid Target Info Example working-directory: ${{github.workspace}}/${{env.BUILD_FOLDER_MSVC_DEV_ALL}} run: | - cmake --build . --target run_hybrid_targetinfo_example_win + cmake --build . --config Release --parallel 2 --target run_hybrid_targetinfo_example_win build_clang: name: Clang single and interface Lib diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ce6173b..dc0fc26b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ option(BUILDCC_FLATBUFFERS_FLATC "Build Flatbuffer::Flatc Compiler" ON) option(BUILDCC_BUILD_AS_SINGLE_LIB "Build all internal libs and modules as part of the buildcc library" ON) option(BUILDCC_BUILD_AS_INTERFACE "Build all internal libs and modules seperately and link" OFF) +option(BUILDCC_BOOTSTRAP_THROUGH_CMAKE "Bootstrap buildcc through CMake" OFF) + # NOTE, Conflict with Clang-Tidy on certain compilers option(BUILDCC_PRECOMPILE_HEADERS "Enable Buildcc precompile headers" OFF) option(BUILDCC_EXAMPLES "Enable Buildcc Examples" OFF) @@ -70,15 +72,10 @@ include(cmake/tool/doxygen.cmake) # Libraries include(cmake/target/flatbuffers.cmake) - include(cmake/target/fmt.cmake) - include(cmake/target/spdlog.cmake) - include(cmake/target/cli11.cmake) - include(cmake/target/taskflow.cmake) - include(cmake/target/tpl.cmake) if (${TESTING}) @@ -117,3 +114,7 @@ if (${BUILDCC_EXAMPLES}) add_subdirectory(example/hybrid/dep_chaining) add_subdirectory(example/hybrid/target_info) endif() + +if (${BUILDCC_BOOTSTRAP_THROUGH_CMAKE}) + add_subdirectory(bootstrap) +endif() diff --git a/CMakePresets.json b/CMakePresets.json index b645b1a2..45c4fa20 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -20,6 +20,7 @@ "BUILDCC_FLATBUFFERS_FLATC": true, "BUILDCC_BUILD_AS_SINGLE_LIB": true, "BUILDCC_BUILD_AS_INTERFACE": true, + "BUILDCC_BOOTSTRAP_THROUGH_CMAKE": true, "BUILDCC_PRECOMPILE_HEADERS": true, "BUILDCC_EXAMPLES": true, "BUILDCC_TESTING": true, @@ -43,6 +44,7 @@ "BUILDCC_FLATBUFFERS_FLATC": true, "BUILDCC_BUILD_AS_SINGLE_LIB": true, "BUILDCC_BUILD_AS_INTERFACE": false, + "BUILDCC_BOOTSTRAP_THROUGH_CMAKE": true, "BUILDCC_PRECOMPILE_HEADERS": true, "BUILDCC_EXAMPLES": true, "BUILDCC_TESTING": true, @@ -66,6 +68,7 @@ "BUILDCC_FLATBUFFERS_FLATC": true, "BUILDCC_BUILD_AS_SINGLE_LIB": false, "BUILDCC_BUILD_AS_INTERFACE": true, + "BUILDCC_BOOTSTRAP_THROUGH_CMAKE": false, "BUILDCC_PRECOMPILE_HEADERS": true, "BUILDCC_EXAMPLES": false, "BUILDCC_TESTING": true, @@ -89,6 +92,7 @@ "BUILDCC_FLATBUFFERS_FLATC": true, "BUILDCC_BUILD_AS_SINGLE_LIB": true, "BUILDCC_BUILD_AS_INTERFACE": true, + "BUILDCC_BOOTSTRAP_THROUGH_CMAKE": true, "BUILDCC_PRECOMPILE_HEADERS": true, "BUILDCC_EXAMPLES": true, "BUILDCC_TESTING": false, @@ -109,6 +113,7 @@ "BUILDCC_FLATBUFFERS_FLATC": true, "BUILDCC_BUILD_AS_SINGLE_LIB": true, "BUILDCC_BUILD_AS_INTERFACE": true, + "BUILDCC_BOOTSTRAP_THROUGH_CMAKE": true, "BUILDCC_PRECOMPILE_HEADERS": true, "BUILDCC_EXAMPLES": true, "BUILDCC_TESTING": false, @@ -129,6 +134,7 @@ "BUILDCC_FLATBUFFERS_FLATC": true, "BUILDCC_BUILD_AS_SINGLE_LIB": true, "BUILDCC_BUILD_AS_INTERFACE": false, + "BUILDCC_BOOTSTRAP_THROUGH_CMAKE": false, "BUILDCC_PRECOMPILE_HEADERS": false, "BUILDCC_EXAMPLES": false, "BUILDCC_TESTING": false, diff --git a/bootstrap/.gitignore b/bootstrap/.gitignore new file mode 100644 index 00000000..cf658897 --- /dev/null +++ b/bootstrap/.gitignore @@ -0,0 +1 @@ +*.dot diff --git a/bootstrap/CMakeLists.txt b/bootstrap/CMakeLists.txt new file mode 100644 index 00000000..42e62912 --- /dev/null +++ b/bootstrap/CMakeLists.txt @@ -0,0 +1,49 @@ +add_executable(buildcc_lib_bootstrap + main.buildcc.cpp +) +target_sources(buildcc_lib_bootstrap PRIVATE + src/build_flatbuffers.cpp + src/build_cli11.cpp + src/build_fmtlib.cpp + src/build_spdlog.cpp + src/build_taskflow.cpp + src/build_tpl.cpp + + src/build_buildcc.cpp +) +target_include_directories(buildcc_lib_bootstrap PRIVATE + include +) +target_link_libraries(buildcc_lib_bootstrap PRIVATE buildcc) + +# TODO, Add this only if MINGW is used +# https://github.com/msys2/MINGW-packages/issues/2303 +# Similar issue when adding the Taskflow library +if (${MINGW}) + message(WARNING "-Wl,--allow-multiple-definition for MINGW") + target_link_options(buildcc_lib_bootstrap PRIVATE -Wl,--allow-multiple-definition) +endif() + +# Linux GCC +add_custom_target(run_buildcc_lib_bootstrap_linux_gcc + COMMAND buildcc_lib_bootstrap --help-all + COMMAND buildcc_lib_bootstrap --config ${CMAKE_CURRENT_SOURCE_DIR}/config_default.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/config/toolchain_gcc_linux.toml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM USES_TERMINAL +) + +# Win GCC/MINGW +add_custom_target(run_buildcc_lib_bootstrap_win_gcc + COMMAND buildcc_lib_bootstrap --help-all + COMMAND buildcc_lib_bootstrap --config ${CMAKE_CURRENT_SOURCE_DIR}/config_default.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/config/toolchain_gcc_win.toml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM USES_TERMINAL +) + +# Win MSVC +add_custom_target(run_buildcc_lib_bootstrap_win_msvc + COMMAND buildcc_lib_bootstrap --help-all + COMMAND buildcc_lib_bootstrap --config ${CMAKE_CURRENT_SOURCE_DIR}/config_default.toml --config ${CMAKE_CURRENT_SOURCE_DIR}/config/toolchain_msvc_win.toml + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + VERBATIM USES_TERMINAL +) diff --git a/bootstrap/config/toolchain_gcc_linux.toml b/bootstrap/config/toolchain_gcc_linux.toml new file mode 100644 index 00000000..6ac3dd34 --- /dev/null +++ b/bootstrap/config/toolchain_gcc_linux.toml @@ -0,0 +1,11 @@ +[toolchain.custom] +build = true +test = true + +id = "gcc" +name = "x86_64-linux-gnu" +asm_compiler = "as" +c_compiler = "gcc" +cpp_compiler = "g++" +archiver = "ar" +linker = "ld" diff --git a/bootstrap/config/toolchain_gcc_win.toml b/bootstrap/config/toolchain_gcc_win.toml new file mode 100644 index 00000000..dfd67809 --- /dev/null +++ b/bootstrap/config/toolchain_gcc_win.toml @@ -0,0 +1,11 @@ +[toolchain.custom] +build = true +test = true + +id = "gcc" +name = "x86_64-w64-mingw32" +asm_compiler = "as" +c_compiler = "gcc" +cpp_compiler = "g++" +archiver = "ar" +linker = "ld" diff --git a/bootstrap/config/toolchain_msvc_win.toml b/bootstrap/config/toolchain_msvc_win.toml new file mode 100644 index 00000000..f14f51e5 --- /dev/null +++ b/bootstrap/config/toolchain_msvc_win.toml @@ -0,0 +1,11 @@ +[toolchain.custom] +build = true +test = true + +id = "msvc" +name = "msvc_x64" +asm_compiler = "cl" +c_compiler = "cl" +cpp_compiler = "cl" +archiver = "lib" +linker = "link" diff --git a/bootstrap/config_default.toml b/bootstrap/config_default.toml new file mode 100644 index 00000000..a3134757 --- /dev/null +++ b/bootstrap/config_default.toml @@ -0,0 +1,5 @@ +root_dir=".." +build_dir="../_build_bootstrap" + +loglevel="trace" +clean=false diff --git a/bootstrap/include/bootstrap/build_buildcc.h b/bootstrap/include/bootstrap/build_buildcc.h new file mode 100644 index 00000000..a0c37e09 --- /dev/null +++ b/bootstrap/include/bootstrap/build_buildcc.h @@ -0,0 +1,33 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_BUILDCC_H_ +#define BOOTSTRAP_BUILD_BUILDCC_H_ + +#include "buildcc.h" + +namespace buildcc { + +void schema_gen_cb(BaseGenerator &generator, const BaseTarget &flatc_exe); + +void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen, + const TargetInfo &flatbuffers_ho, const TargetInfo &fmt_ho, + const TargetInfo &spdlog_ho, const TargetInfo &cli11_ho, + const TargetInfo &taskflow_ho, const BaseTarget &tpl); + +} // namespace buildcc + +#endif diff --git a/bootstrap/include/bootstrap/build_cli11.h b/bootstrap/include/bootstrap/build_cli11.h new file mode 100644 index 00000000..2f0d0952 --- /dev/null +++ b/bootstrap/include/bootstrap/build_cli11.h @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_CLI11_H_ +#define BOOTSTRAP_BUILD_CLI11_H_ + +#include "buildcc.h" + +namespace buildcc { + +void cli11_ho_cb(TargetInfo &info); + +} // namespace buildcc + +#endif diff --git a/bootstrap/include/bootstrap/build_flatbuffers.h b/bootstrap/include/bootstrap/build_flatbuffers.h new file mode 100644 index 00000000..d0adf845 --- /dev/null +++ b/bootstrap/include/bootstrap/build_flatbuffers.h @@ -0,0 +1,29 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_FLATBUFFERS_H_ +#define BOOTSTRAP_BUILD_FLATBUFFERS_H_ + +#include "buildcc.h" + +namespace buildcc { + +void build_flatc_exe_cb(BaseTarget &target); +void flatbuffers_ho_cb(TargetInfo &info); + +} // namespace buildcc + +#endif diff --git a/bootstrap/include/bootstrap/build_fmtlib.h b/bootstrap/include/bootstrap/build_fmtlib.h new file mode 100644 index 00000000..a09fd383 --- /dev/null +++ b/bootstrap/include/bootstrap/build_fmtlib.h @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_FMTLIB_H_ +#define BOOTSTRAP_BUILD_FMTLIB_H_ + +#include "buildcc.h" + +namespace buildcc { + +void fmt_ho_cb(TargetInfo &info); + +} // namespace buildcc + +#endif diff --git a/bootstrap/include/bootstrap/build_spdlog.h b/bootstrap/include/bootstrap/build_spdlog.h new file mode 100644 index 00000000..f71dab43 --- /dev/null +++ b/bootstrap/include/bootstrap/build_spdlog.h @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_SPDLOG_H_ +#define BOOTSTRAP_BUILD_SPDLOG_H_ + +#include "buildcc.h" + +namespace buildcc { + +void spdlog_ho_cb(TargetInfo &info); + +} // namespace buildcc + +#endif diff --git a/bootstrap/include/bootstrap/build_taskflow.h b/bootstrap/include/bootstrap/build_taskflow.h new file mode 100644 index 00000000..f0a70250 --- /dev/null +++ b/bootstrap/include/bootstrap/build_taskflow.h @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_TASKFLOW_H_ +#define BOOTSTRAP_BUILD_TASKFLOW_H_ + +#include "buildcc.h" + +namespace buildcc { + +void taskflow_ho_cb(TargetInfo &info); + +} // namespace buildcc + +#endif diff --git a/bootstrap/include/bootstrap/build_tpl.h b/bootstrap/include/bootstrap/build_tpl.h new file mode 100644 index 00000000..5ac24653 --- /dev/null +++ b/bootstrap/include/bootstrap/build_tpl.h @@ -0,0 +1,28 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BOOTSTRAP_BUILD_TPL_H_ +#define BOOTSTRAP_BUILD_TPL_H_ + +#include "buildcc.h" + +namespace buildcc { + +void tpl_cb(BaseTarget &target); + +} // namespace buildcc + +#endif diff --git a/bootstrap/main.buildcc.cpp b/bootstrap/main.buildcc.cpp new file mode 100644 index 00000000..f5569183 --- /dev/null +++ b/bootstrap/main.buildcc.cpp @@ -0,0 +1,179 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "buildcc.h" + +#include "bootstrap/build_cli11.h" +#include "bootstrap/build_flatbuffers.h" +#include "bootstrap/build_fmtlib.h" +#include "bootstrap/build_spdlog.h" +#include "bootstrap/build_taskflow.h" +#include "bootstrap/build_tpl.h" + +#include "bootstrap/build_buildcc.h" + +using namespace buildcc; + +static void clean_cb(); +static void global_flags_cb(TargetInfo &global_info, + const BaseToolchain &toolchain); + +static void setup_buildcc_cb(PersistentStorage &storage, Register ®, + const Args::ToolchainArg &custom_toolchain_arg, + const BaseToolchain &toolchain); + +static void hybrid_simple_example_cb(BaseTarget &target, + const BaseTarget &libbuildcc); + +int main(int argc, char **argv) { + Args args; + Args::ToolchainArg custom_toolchain_arg; + args.AddToolchain("custom", "Host Toolchain", custom_toolchain_arg); + args.Parse(argc, argv); + + Register reg(args); + reg.Clean(clean_cb); + + BaseToolchain toolchain = custom_toolchain_arg.ConstructToolchain(); + + PersistentStorage storage; + setup_buildcc_cb(storage, reg, custom_toolchain_arg, toolchain); + + const StaticTarget_generic &buildcc_lib = + storage.ConstRef("libbuildcc"); + + ExecutableTarget_generic buildcc_hybrid_simple_example( + "buildcc_hybrid_simple_example", toolchain, "example/hybrid/simple"); + reg.Build(custom_toolchain_arg.state, hybrid_simple_example_cb, + buildcc_hybrid_simple_example, buildcc_lib); + reg.Dep(buildcc_hybrid_simple_example, buildcc_lib); + + // Runners + reg.RunBuild(); + reg.RunTest(); + + // - Clang Compile Commands + plugin::ClangCompileCommands({&buildcc_lib}).Generate(); + + // - Plugin Graph + std::string output = reg.GetTaskflow().dump(); + const bool saved = env::save_file("graph.dot", output, false); + env::assert_fatal(saved, "Could not save graph.dot file"); + + return 0; +} + +static void clean_cb() {} + +static void global_flags_cb(TargetInfo &global_info, + const BaseToolchain &toolchain) { + // TODO, Clang + switch (toolchain.GetId()) { + case ToolchainId::Gcc: + case ToolchainId::MinGW: + global_info.AddCppCompileFlag("-std=c++17"); + global_info.AddCppCompileFlag("-Os"); + global_info.AddCppCompileFlag("-Wall"); + global_info.AddCppCompileFlag("-Wextra"); + global_info.AddCppCompileFlag("-Werror"); + break; + case ToolchainId::Msvc: + global_info.AddPreprocessorFlag("/D_CRT_SECURE_NO_WARNINGS"); + global_info.AddCppCompileFlag("/std:c++17"); + global_info.AddCppCompileFlag("/Ot"); + global_info.AddCppCompileFlag("/W4"); + global_info.AddCppCompileFlag("/WX"); + default: + break; + } +} + +static void setup_buildcc_cb(PersistentStorage &storage, Register ®, + const Args::ToolchainArg &custom_toolchain_arg, + const BaseToolchain &toolchain) { + + // Flatc Executable + ExecutableTarget_generic &flatc_exe = storage.Add( + "flatc", "flatc", toolchain, "third_party/flatbuffers"); + reg.CallbackIf(custom_toolchain_arg.state, global_flags_cb, flatc_exe, + toolchain); + reg.Build(custom_toolchain_arg.state, build_flatc_exe_cb, flatc_exe); + + // Schema + BaseGenerator &schema_gen = + storage.Add("schema_gen", "schema_gen", "buildcc/schema"); + reg.Build(schema_gen_cb, schema_gen, flatc_exe); + reg.Dep(schema_gen, flatc_exe); + + // Flatbuffers HO lib + TargetInfo &flatbuffers_ho_lib = + storage.Add("flatbuffers_ho", "third_party/flatbuffers"); + reg.Callback(flatbuffers_ho_cb, flatbuffers_ho_lib); + + // CLI11 HO lib + TargetInfo &cli11_ho_lib = + storage.Add("cli11_ho", "third_party/CLI11"); + reg.Callback(cli11_ho_cb, cli11_ho_lib); + + // fmt HO lib + TargetInfo &fmt_ho_lib = storage.Add("fmt_ho", "third_party/fmt"); + reg.Callback(fmt_ho_cb, fmt_ho_lib); + + // spdlog HO lib + TargetInfo &spdlog_ho_lib = + storage.Add("spdlog_ho", "third_party/spdlog"); + reg.Callback(spdlog_ho_cb, spdlog_ho_lib); + + // taskflow HO lib + TargetInfo &taskflow_ho_lib = + storage.Add("taskflow_ho", "third_party/taskflow"); + reg.Callback(taskflow_ho_cb, taskflow_ho_lib); + + // Tiny-process-library lib + // TODO, Make this a generic selection between StaticTarget and DynamicTarget + StaticTarget_generic &tpl_lib = storage.Add( + "libtpl", "libtpl", toolchain, "third_party/tiny-process-library"); + reg.CallbackIf(custom_toolchain_arg.state, global_flags_cb, tpl_lib, + toolchain); + reg.Build(custom_toolchain_arg.state, tpl_cb, tpl_lib); + + // TODO, Make this a generic selection between StaticTarget and DynamicTarget + StaticTarget_generic &buildcc_lib = storage.Add( + "libbuildcc", "libbuildcc", toolchain, "buildcc"); + reg.CallbackIf(custom_toolchain_arg.state, global_flags_cb, buildcc_lib, + toolchain); + reg.Build(custom_toolchain_arg.state, buildcc_cb, buildcc_lib, schema_gen, + flatbuffers_ho_lib, fmt_ho_lib, spdlog_ho_lib, cli11_ho_lib, + taskflow_ho_lib, tpl_lib); + reg.Dep(buildcc_lib, schema_gen); + reg.Dep(buildcc_lib, tpl_lib); +} + +static void hybrid_simple_example_cb(BaseTarget &target, + const BaseTarget &libbuildcc) { + target.Insert(libbuildcc, { + SyncOption::PreprocessorFlags, + SyncOption::CppCompileFlags, + SyncOption::LinkFlags, + SyncOption::HeaderFiles, + SyncOption::IncludeDirs, + SyncOption::LibDeps, + SyncOption::ExternalLibDeps, + }); + target.AddSource("build.cpp"); + target.AddLibDep(libbuildcc); + target.Build(); +} diff --git a/bootstrap/src/build_buildcc.cpp b/bootstrap/src/build_buildcc.cpp new file mode 100644 index 00000000..7432964a --- /dev/null +++ b/bootstrap/src/build_buildcc.cpp @@ -0,0 +1,162 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_buildcc.h" + +namespace buildcc { + +void schema_gen_cb(BaseGenerator &generator, const BaseTarget &flatc_exe) { + generator.AddInput("{gen_root_dir}/path.fbs", "path_fbs"); + generator.AddInput("{gen_root_dir}/generator.fbs", "generator_fbs"); + generator.AddInput("{gen_root_dir}/target.fbs", "target_fbs"); + + generator.AddOutput("{gen_build_dir}/path_generated.h"); + generator.AddOutput("{gen_build_dir}/generator_generated.h"); + generator.AddOutput("{gen_build_dir}/target_generated.h"); + + generator.AddDefaultArguments({ + {"flatc_compiler", fmt::format("{}", flatc_exe.GetTargetPath())}, + }); + // generator.AddCommand("{flatc_compiler} --help"); + generator.AddCommand( + "{flatc_compiler} -o {gen_build_dir} -I {gen_root_dir} --gen-object-api " + "--cpp {path_fbs} {generator_fbs} {target_fbs}"); + + generator.Build(); +} + +void buildcc_cb(BaseTarget &target, const BaseGenerator &schema_gen, + const TargetInfo &flatbuffers_ho, const TargetInfo &fmt_ho, + const TargetInfo &spdlog_ho, const TargetInfo &cli11_ho, + const TargetInfo &taskflow_ho, const BaseTarget &tpl) { + // NOTE, Build as single lib + target.AddIncludeDir("", true); + const std::string &schema_build_dir = + schema_gen.GetValueByIdentifier("gen_build_dir"); + target.AddIncludeDirAbsolute(schema_build_dir, true); + + // ENV + target.GlobSources("lib/env/src"); + target.AddIncludeDir("lib/env/include"); + target.GlobHeaders("lib/env/include/env"); + + // COMMAND + target.GlobSources("lib/command/src"); + target.AddIncludeDir("lib/command/include"); + target.GlobHeaders("lib/command/include/command"); + + // TOOLCHAIN + target.AddIncludeDir("lib/toolchain/include"); + target.GlobHeaders("lib/toolchain/include/toolchain"); + + // TARGET + target.GlobSources("lib/target/src/common"); + target.GlobSources("lib/target/src/generator"); + target.GlobSources("lib/target/src/api"); + target.GlobSources("lib/target/src/target"); + target.GlobSources("lib/target/src/target/friend"); + + target.AddIncludeDir("lib/target/include"); + target.GlobHeaders("lib/target/include/target"); + target.GlobHeaders("lib/target/include/target/api"); + target.GlobHeaders("lib/target/include/target/base"); + target.GlobHeaders("lib/target/include/target/common"); + target.GlobHeaders("lib/target/include/target/friend"); + target.GlobHeaders("lib/target/include/target/interface"); + target.GlobHeaders("lib/target/include/target/private"); + + // ARGS + target.GlobSources("lib/args/src"); + target.AddIncludeDir("lib/args/include"); + target.GlobHeaders("lib/args/include/args"); + + // Specialized Toolchains + target.AddIncludeDir("toolchains/include"); + target.GlobHeaders("toolchains/include/toolchains"); + + // Specialized Targets + target.AddIncludeDir("targets/include"); + target.GlobHeaders("targets/include/targets"); + + // Plugins + target.GlobSources("plugins/src"); + target.AddIncludeDir("plugins/include"); + target.GlobHeaders("plugins/include/plugins"); + + // Third Party libraries + + const std::initializer_list kInsertOptions{ + SyncOption::IncludeDirs, + SyncOption::HeaderFiles, + }; + + // FLATBUFFERS HO + target.Insert(flatbuffers_ho, kInsertOptions); + + // FMT HO + target.Insert(fmt_ho, kInsertOptions); + + // SPDLOG HO + target.Insert(spdlog_ho, kInsertOptions); + + // CLI11 HO + target.Insert(cli11_ho, kInsertOptions); + + // TASKFLOW HO + target.Insert(taskflow_ho, kInsertOptions); + + // TPL LIB + target.AddLibDep(tpl); + target.Insert(tpl, kInsertOptions); + + if constexpr (env::is_win()) { + // TODO, Clang + switch (target.GetToolchain().GetId()) { + case ToolchainId::Gcc: + case ToolchainId::MinGW: { + target.AddPreprocessorFlag("-DFMT_HEADER_ONLY=1"); + target.AddPreprocessorFlag("-DSPDLOG_FMT_EXTERNAL"); + // For MINGW + target.AddLinkFlag("-Wl,--allow-multiple-definition"); + } break; + case ToolchainId::Msvc: { + target.AddPreprocessorFlag("/DFMT_HEADER_ONLY=1"); + target.AddPreprocessorFlag("/DSPDLOG_FMT_EXTERNAL"); + } break; + default: + break; + } + } + + if constexpr (env::is_linux()) { + // TODO, Clang + switch (target.GetToolchain().GetId()) { + case ToolchainId::Gcc: { + target.AddPreprocessorFlag("-DFMT_HEADER_ONLY=1"); + target.AddPreprocessorFlag("-DSPDLOG_FMT_EXTERNAL"); + target.AddLibDep("-lpthread"); + } break; + default: + break; + } + } + + // TODO, Other OS's + + target.Build(); +} + +} // namespace buildcc diff --git a/bootstrap/src/build_cli11.cpp b/bootstrap/src/build_cli11.cpp new file mode 100644 index 00000000..fa900aa7 --- /dev/null +++ b/bootstrap/src/build_cli11.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_cli11.h" + +namespace buildcc { + +void cli11_ho_cb(TargetInfo &info) { + info.AddIncludeDir("include"); + info.GlobHeaders("include/CLI"); + // TODO, Add PCH +} + +} // namespace buildcc diff --git a/bootstrap/src/build_flatbuffers.cpp b/bootstrap/src/build_flatbuffers.cpp new file mode 100644 index 00000000..01039ae0 --- /dev/null +++ b/bootstrap/src/build_flatbuffers.cpp @@ -0,0 +1,126 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_flatbuffers.h" + +namespace { + +const std::vector kFlatcSources{ + "code_generators.cpp", + "flatc_main.cpp", + "flatc.cpp", + "idl_gen_cpp.cpp", + "idl_gen_csharp.cpp", + "idl_gen_dart.cpp", + "idl_gen_fbs.cpp", + "idl_gen_go.cpp", + "idl_gen_grpc.cpp", + "idl_gen_java.cpp", + "idl_gen_json_schema.cpp", + "idl_gen_kotlin.cpp", + "idl_gen_lobster.cpp", + "idl_gen_lua.cpp", + "idl_gen_php.cpp", + "idl_gen_python.cpp", + "idl_gen_rust.cpp", + "idl_gen_swift.cpp", + "idl_gen_text.cpp", + "idl_gen_ts.cpp", + "idl_parser.cpp", + "reflection.cpp", + "util.cpp", +}; + +const std::vector kFlatcPreprocessorFlags{ + "-DFLATBUFFERS_LOCALE_INDEPENDENT=0", + "-DNDEBUG", +}; + +const std::vector kFlatcGccCppCompileFlags{ + "-pedantic", "-Werror=shadow", + "-faligned-new", "-Werror=implicit-fallthrough=2", + "-Wunused-result", "-Werror=unused-result", + "-Wunused-parameter", "-Werror=unused-parameter", + "-fsigned-char", "-Wold-style-cast", + "-Winvalid-pch", +}; + +const std::vector kFlatcMsvcCppCompileFlags{ + "/MP", "/MT", "/GS", "/GR", + "/fp:precise", "/Zc:wchar_t", "/Zc:forScope", "/Zc:inline", +}; + +} // namespace + +namespace buildcc { + +void build_flatc_exe_cb(BaseTarget &target) { + std::for_each(kFlatcSources.cbegin(), kFlatcSources.cend(), + [&](const auto &s) { target.AddSource(s, "src"); }); + target.GlobSources("grpc/src/compiler"); + + target.AddIncludeDir("include"); + target.AddIncludeDir("grpc"); + + target.GlobHeaders("include/flatbuffers"); + target.GlobHeaders("grpc/src/compiler"); + + std::for_each(kFlatcPreprocessorFlags.cbegin(), + kFlatcPreprocessorFlags.cend(), + [&](const auto &f) { target.AddPreprocessorFlag(f); }); + + if constexpr (env::is_win()) { + switch (target.GetToolchain().GetId()) { + case ToolchainId::Gcc: + case ToolchainId::MinGW: + std::for_each(kFlatcGccCppCompileFlags.cbegin(), + kFlatcGccCppCompileFlags.cend(), + [&](const auto &f) { target.AddCppCompileFlag(f); }); + break; + case ToolchainId::Msvc: + std::for_each(kFlatcMsvcCppCompileFlags.cbegin(), + kFlatcMsvcCppCompileFlags.cend(), + [&](const auto &f) { target.AddCppCompileFlag(f); }); + break; + default: + break; + } + } + + if constexpr (env::is_linux()) { + switch (target.GetToolchain().GetId()) { + case ToolchainId::Gcc: + std::for_each(kFlatcGccCppCompileFlags.cbegin(), + kFlatcGccCppCompileFlags.cend(), + [&](const auto &f) { target.AddCppCompileFlag(f); }); + break; + default: + break; + } + } + + // TODO, Add PCH + + target.Build(); +} + +void flatbuffers_ho_cb(TargetInfo &info) { + info.AddIncludeDir("include"); + info.GlobHeaders("include/flatbuffers"); + // TODO, Add PCH +} + +} // namespace buildcc diff --git a/bootstrap/src/build_fmtlib.cpp b/bootstrap/src/build_fmtlib.cpp new file mode 100644 index 00000000..0ce2aa34 --- /dev/null +++ b/bootstrap/src/build_fmtlib.cpp @@ -0,0 +1,26 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_fmtlib.h" + +namespace buildcc { + +void fmt_ho_cb(TargetInfo &info) { + info.AddIncludeDir("include"); + info.GlobHeaders("include/fmt"); +} + +} // namespace buildcc diff --git a/bootstrap/src/build_spdlog.cpp b/bootstrap/src/build_spdlog.cpp new file mode 100644 index 00000000..483807fe --- /dev/null +++ b/bootstrap/src/build_spdlog.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_spdlog.h" + +namespace buildcc { + +void spdlog_ho_cb(TargetInfo &info) { + info.AddIncludeDir("include"); + info.GlobHeaders("include/spdlog"); + info.GlobHeaders("include/spdlog/cfg"); + info.GlobHeaders("include/spdlog/details"); + info.GlobHeaders("include/spdlog/fmt"); + info.GlobHeaders("include/spdlog/sinks"); +} + +} // namespace buildcc diff --git a/bootstrap/src/build_taskflow.cpp b/bootstrap/src/build_taskflow.cpp new file mode 100644 index 00000000..9d945194 --- /dev/null +++ b/bootstrap/src/build_taskflow.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_taskflow.h" + +namespace buildcc { + +void taskflow_ho_cb(TargetInfo &info) { + info.AddIncludeDir(""); + info.GlobHeaders("taskflow"); + info.GlobHeaders("taskflow/core"); + info.GlobHeaders("taskflow/core/algorithm"); + // TODO, Track more header files +} + +} // namespace buildcc diff --git a/bootstrap/src/build_tpl.cpp b/bootstrap/src/build_tpl.cpp new file mode 100644 index 00000000..5fbdf513 --- /dev/null +++ b/bootstrap/src/build_tpl.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bootstrap/build_tpl.h" + +namespace buildcc { + +void tpl_cb(BaseTarget &target) { + target.AddSource("process.cpp"); + target.AddIncludeDir(""); + target.AddHeader("process.hpp"); + + if constexpr (env::is_win()) { + target.AddSource("process_win.cpp"); + } else { + target.AddSource("process_unix.cpp"); + } + + target.Build(); +} + +} // namespace buildcc diff --git a/buildcc/buildcc.h b/buildcc/buildcc.h index 6d7ca2f2..8e533a96 100644 --- a/buildcc/buildcc.h +++ b/buildcc/buildcc.h @@ -57,5 +57,6 @@ // BuildCC Modules #include "args/args.h" #include "args/register.h" +#include "args/persistent_storage.h" #endif diff --git a/buildcc/lib/args/CMakeLists.txt b/buildcc/lib/args/CMakeLists.txt index 949b51b1..c2f2d3a3 100644 --- a/buildcc/lib/args/CMakeLists.txt +++ b/buildcc/lib/args/CMakeLists.txt @@ -40,12 +40,20 @@ target_link_libraries(test_register PRIVATE mock_args ) +add_executable(test_persistent_storage + test/test_persistent_storage.cpp +) +target_link_libraries(test_persistent_storage PRIVATE mock_args) + add_test(NAME test_args COMMAND test_args WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test ) add_test(NAME test_register COMMAND test_register WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test ) +add_test(NAME test_persistent_storage COMMAND test_persistent_storage + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test +) endif() set(ARGS_SRCS @@ -55,6 +63,7 @@ set(ARGS_SRCS src/tasks.cpp include/args/args.h include/args/register.h + include/args/persistent_storage.h ) if(${BUILDCC_BUILD_AS_SINGLE_LIB}) diff --git a/buildcc/lib/args/include/args/args.h b/buildcc/lib/args/include/args/args.h index be325c44..99f9f06f 100644 --- a/buildcc/lib/args/include/args/args.h +++ b/buildcc/lib/args/include/args/args.h @@ -66,7 +66,7 @@ class Args { cpp_compiler(initial_cpp_compiler), archiver(initial_archiver), linker(initial_linker) {} - base::Toolchain ConstructToolchain() { + base::Toolchain ConstructToolchain() const { base::Toolchain toolchain(id, name, asm_compiler, c_compiler, cpp_compiler, archiver, linker); return toolchain; diff --git a/buildcc/lib/args/include/args/persistent_storage.h b/buildcc/lib/args/include/args/persistent_storage.h new file mode 100644 index 00000000..4c3c5b73 --- /dev/null +++ b/buildcc/lib/args/include/args/persistent_storage.h @@ -0,0 +1,95 @@ +/* + * Copyright 2021 Niket Naidu. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ARGS_PERSISTENT_STORAGE_H_ +#define ARGS_PERSISTENT_STORAGE_H_ + +#include +#include +#include +#include + +#include "env/assert_fatal.h" + +#include "fmt/format.h" + +namespace buildcc { + +class PersistentStorage { +public: + PersistentStorage() {} + ~PersistentStorage() { + for (const auto &ptr_iter : ptrs_) { + ptr_iter.second.destructor(); + } + ptrs_.clear(); + env::assert_fatal(ptrs_.empty(), "Memory not deallocated"); + } + + template + T &Add(const std::string &identifier, Params &&...params) { + T *ptr = new T(std::forward(params)...); + env::assert_fatal(ptr != nullptr, "System out of memory"); + + PtrMetadata metadata; + metadata.ptr = (void *)ptr; + metadata.typeid_name = typeid(T).name(); + metadata.destructor = [this, identifier, ptr]() { + env::log_info("Cleaning", identifier); + Remove(ptr); + }; + ptrs_.emplace(identifier, metadata); + return *ptr; + } + + template void Remove(T *ptr) { delete ptr; } + + template const T &ConstRef(const std::string &identifier) const { + const PtrMetadata &metadata = ptrs_.at(identifier); + env::assert_fatal( + typeid(T).name() == metadata.typeid_name, + fmt::format("Wrong type, expects: {}", metadata.typeid_name)); + const T *p = (const T *)metadata.ptr; + return *p; + } + + // https://stackoverflow.com/questions/123758/how-do-i-remove-code-duplication-between-similar-const-and-non-const-member-func/123995 + template T &Ref(const std::string &identifier) { + return const_cast( + static_cast(*this).ConstRef(identifier)); + } + +private: + /** + * @brief + * @param ptr Can hold data of any type + * @param typeid_name We cannot store a template type so this is the next best + * thing + * @param desstructor Destructor callback to delete ptr + */ + struct PtrMetadata { + void *ptr; + std::string typeid_name; + std::function destructor; + }; + +private: + std::unordered_map ptrs_; +}; + +} // namespace buildcc + +#endif diff --git a/buildcc/lib/args/test/test_persistent_storage.cpp b/buildcc/lib/args/test/test_persistent_storage.cpp new file mode 100644 index 00000000..16079c4e --- /dev/null +++ b/buildcc/lib/args/test/test_persistent_storage.cpp @@ -0,0 +1,60 @@ +#include "args/persistent_storage.h" + +#include "target/generator.h" +#include "target/target.h" + +// NOTE, Make sure all these includes are AFTER the system and header includes +#include "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/MemoryLeakDetectorNewMacros.h" +#include "CppUTest/TestHarness.h" +#include "CppUTest/Utest.h" +#include "CppUTestExt/MockSupport.h" + +// clang-format off +TEST_GROUP(PersistentStorageTestGroup) +{ +}; +// clang-format on + +buildcc::BaseToolchain gcc(buildcc::ToolchainId::Gcc, "gcc", "as", "gcc", "g++", + "ar", "ld"); + +TEST(PersistentStorageTestGroup, BasicUsage) { + buildcc::PersistentStorage persistent; + persistent.Add("target_identifier", "target_name", + buildcc::TargetType::Executable, gcc, ""); + persistent.Add("generator_identifier", + "generator_name", ""); + + // Usage + persistent.ConstRef("target_identifier").GetName(); + persistent.Ref("generator_identifier").GetTaskflow(); + + // Automatic cleanup here +} + +TEST(PersistentStorageTestGroup, IncorrectUsage) { + buildcc::PersistentStorage persistent; + persistent.Add("target_identifier", "target_name", + buildcc::TargetType::Executable, gcc, ""); + + // We try to cast to a different type! + CHECK_THROWS(std::exception, + persistent.Ref("target_identifier")); + + // We use a wrong identifier + CHECK_THROWS(std::exception, + persistent.Ref("generator_identifier")); +} + +std::string &toReference(std::string *pointer) { return *pointer; } + +TEST(PersistentStorageTestGroup, NullptrDelete) { + buildcc::PersistentStorage persistent; + persistent.Remove(nullptr); +} + +int main(int ac, char **av) { + buildcc::env::init(fs::current_path(), fs::current_path()); + return CommandLineTestRunner::RunAllTests(ac, av); +} diff --git a/buildcc/lib/target/include/target/generator.h b/buildcc/lib/target/include/target/generator.h index fe41eabc..b2d6baec 100644 --- a/buildcc/lib/target/include/target/generator.h +++ b/buildcc/lib/target/include/target/generator.h @@ -47,6 +47,7 @@ class Generator : public BuilderInterface { loader_(name, generator_build_dir_), parallel_(parallel) { Initialize(); } + virtual ~Generator() {} Generator(const Generator &generator) = delete; /** @@ -98,8 +99,8 @@ class Generator : public BuilderInterface { const fs::path &GetBinaryPath() const { return loader_.GetBinaryPath(); } tf::Taskflow &GetTaskflow() { return tf_; } - const std::string &GetName() { return name_; } - env::TaskState GetTaskState() { return task_state_; } + const std::string &GetName() const { return name_; } + env::TaskState GetTaskState() const { return task_state_; } const std::string & GetValueByIdentifier(const std::string &file_identifier) const;