diff --git a/.gdb_history b/.gdb_history index c7e43df..0084caf 100644 --- a/.gdb_history +++ b/.gdb_history @@ -12,3 +12,39 @@ up up bt q +r +q +r +up +up +up +up +up +up +up +up +bt +q +r +bt +q +r +bt +q +r +bt +q +q +r +up +up +up +:q +q +r +up +up +up +up +up +q diff --git a/CMakeLists.txt b/CMakeLists.txt index 9dd117c..b728232 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,5 +7,5 @@ add_subdirectory("vendor/sol2") include_directories("include") include_directories("vendor/sol2/include") -add_executable(grbc src/main.cc src/utils.cc src/file.cc src/target_exe.cc src/platform.cc src/ninja.cc src/generator.cc) +add_executable(grbc src/main.cc src/utils.cc src/file.cc src/target_exe.cc src/platform.cc src/ninja.cc src/generator.cc src/target_lib.cc src/package.cc) target_link_libraries(grbc sol2 lua) \ No newline at end of file diff --git a/HConfig b/HConfig index 22d3311..78f4c09 100644 --- a/HConfig +++ b/HConfig @@ -1,17 +1,44 @@ grbc_want_version("1.0") grbc_load_platform("platform.hcfg") +grbc_load_profile("profile.hcfg") + +local grbc_lib = grbc_library(LibraryConfig.new({ + name = "libgrbc", + language_type = LanguageType.Cpp, + files = { + grbc_file("src/file.cc"), + grbc_file("src/ninja.cc"), + grbc_file("src/platform.cc"), + grbc_file("src/target_exe.cc"), + grbc_file("src/utils.cc"), + grbc_file("src/generator.cc"), + grbc_file("src/target_lib.cc"), + grbc_file("src/package.cc") + }, + lib_type = LibraryType.Static, + + requirements = {}, + compile_flags = {}, + linker_flags = {}, + include_dirs = { + grbc_file("include"), + grbc_file("vendor/sol2/include") + }, + + package_config = PackageConfig.new({ + name = "libgrbc", + libraries = {}, + include_dirs = {}, + compile_flags = {}, + linker_flags = {}, + }) +})) local grbc_exe = grbc_executable(ExecutableConfig.new({ name = "grbc", language_type = LanguageType.Cpp, files = { - grbc_file("src/main.cc"), - grbc_file("src/file.cc"), - grbc_file("src/ninja.cc"), - grbc_file("src/platform.cc"), - grbc_file("src/target_exe.cc"), - grbc_file("src/utils.cc"), - grbc_file("src/generator.cc") + grbc_file("src/main.cc"), }, requirements = { @@ -19,9 +46,13 @@ local grbc_exe = grbc_executable(ExecutableConfig.new({ name = "lua", compiler_flags = "", linker_flags = "-llua -lm -ldl" - }) + }), + + grbc_pkg("libgrbc") + }, + compile_flags = { + grbc_compiler_define("HCONFIG", "") }, - compile_flags = {}, linker_flags = {}, include_dirs = { grbc_file("include"), @@ -30,4 +61,4 @@ local grbc_exe = grbc_executable(ExecutableConfig.new({ })) -- Output the final build script -grbc_build("ninja") \ No newline at end of file +grbc_build("ninja") diff --git a/README.md b/README.md index 2eb7e9b..fbe4262 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,11 @@ GRaphite Build Configurator ## About -GRBC is a predictable build system. \ No newline at end of file +GRBC was developed because I hate CMake. I liked the build systems built for zig, and jai, but wanted something for C++. I also enjoyed how Vulkan extensions were managed and took insipiration from them to make grbc extensible. + +## Benifits +* GRBC is fast, almost no wait time for build.ninja generation +* GRBC scripts are easy to read, and predictable +* GRBC produces ninja files which can be ran without grbc installed +* GRBC has cmake interop, so libraries using cmake can still be used +* GRBC is well documented \ No newline at end of file diff --git a/build.ninja b/build.ninja index 23268c8..27d117f 100644 --- a/build.ninja +++ b/build.ninja @@ -26,52 +26,72 @@ rule cxx rule link_cc command = $cc_path $p_cflags -o $out $in $p_linker_flags - description = Linking C executables $out + description = Linking C target $out ## build_rule_link_cxx ## rule link_cxx command = $cxx_path $p_cflags -o $out $in $p_linker_flags - description = Linking C++ executables $out + description = Linking C++ target $out -## Compile: src/main.cc ## +## build_rule_archive_library ## -build $builddir/src/main.o: cxx src/main.cc - p_cflags = -Iinclude -Ivendor/sol2/include +rule archive + command = rm -f $out; ar crs $out $in + description = Creating static library $out ## Compile: src/file.cc ## build $builddir/src/file.o: cxx src/file.cc - p_cflags = -Iinclude -Ivendor/sol2/include + p_cflags = -Iinclude -Ivendor/sol2/include ## Compile: src/ninja.cc ## build $builddir/src/ninja.o: cxx src/ninja.cc - p_cflags = -Iinclude -Ivendor/sol2/include + p_cflags = -Iinclude -Ivendor/sol2/include ## Compile: src/platform.cc ## build $builddir/src/platform.o: cxx src/platform.cc - p_cflags = -Iinclude -Ivendor/sol2/include + p_cflags = -Iinclude -Ivendor/sol2/include ## Compile: src/target_exe.cc ## build $builddir/src/target_exe.o: cxx src/target_exe.cc - p_cflags = -Iinclude -Ivendor/sol2/include + p_cflags = -Iinclude -Ivendor/sol2/include ## Compile: src/utils.cc ## build $builddir/src/utils.o: cxx src/utils.cc - p_cflags = -Iinclude -Ivendor/sol2/include + p_cflags = -Iinclude -Ivendor/sol2/include ## Compile: src/generator.cc ## build $builddir/src/generator.o: cxx src/generator.cc - p_cflags = -Iinclude -Ivendor/sol2/include + p_cflags = -Iinclude -Ivendor/sol2/include + +## Compile: src/target_lib.cc ## + +build $builddir/src/target_lib.o: cxx src/target_lib.cc + p_cflags = -Iinclude -Ivendor/sol2/include + +## Compile: src/package.cc ## + +build $builddir/src/package.o: cxx src/package.cc + p_cflags = -Iinclude -Ivendor/sol2/include + +## Link: libgrbc.a ## + +build $builddir/libgrbc.a: archive $builddir/src/file.o $builddir/src/ninja.o $builddir/src/platform.o $builddir/src/target_exe.o $builddir/src/utils.o $builddir/src/generator.o $builddir/src/target_lib.o $builddir/src/package.o + +## Compile: src/main.cc ## + +build $builddir/src/main.o: cxx src/main.cc + p_cflags = -fdiagnostics-color=always -DHCONFIG= -Iinclude -Ivendor/sol2/include ## Link: grbc ## -build grbc: link_cxx $builddir/src/main.o $builddir/src/file.o $builddir/src/ninja.o $builddir/src/platform.o $builddir/src/target_exe.o $builddir/src/utils.o $builddir/src/generator.o - p_linker_flags = -llua -lm -ldl +build $builddir/grbc: link_cxx $builddir/src/main.o + p_linker_flags = -llua -lm -ldl build/libgrbc.a p_cflags = diff --git a/compile_commands.json b/compile_commands.json index e47e92b..b0c89fa 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -7,49 +7,49 @@ }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/main.cc.o -MF CMakeFiles/grbc.dir/src/main.cc.o.d -o CMakeFiles/grbc.dir/src/main.cc.o -c /home/interfiber/dev/grbc/src/main.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/main.cc.o -MF CMakeFiles/grbc.dir/src/main.cc.o.d -o CMakeFiles/grbc.dir/src/main.cc.o -c /home/interfiber/dev/grbc/src/main.cc", "file": "/home/interfiber/dev/grbc/src/main.cc", "output": "CMakeFiles/grbc.dir/src/main.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/utils.cc.o -MF CMakeFiles/grbc.dir/src/utils.cc.o.d -o CMakeFiles/grbc.dir/src/utils.cc.o -c /home/interfiber/dev/grbc/src/utils.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/utils.cc.o -MF CMakeFiles/grbc.dir/src/utils.cc.o.d -o CMakeFiles/grbc.dir/src/utils.cc.o -c /home/interfiber/dev/grbc/src/utils.cc", "file": "/home/interfiber/dev/grbc/src/utils.cc", "output": "CMakeFiles/grbc.dir/src/utils.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/file.cc.o -MF CMakeFiles/grbc.dir/src/file.cc.o.d -o CMakeFiles/grbc.dir/src/file.cc.o -c /home/interfiber/dev/grbc/src/file.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/file.cc.o -MF CMakeFiles/grbc.dir/src/file.cc.o.d -o CMakeFiles/grbc.dir/src/file.cc.o -c /home/interfiber/dev/grbc/src/file.cc", "file": "/home/interfiber/dev/grbc/src/file.cc", "output": "CMakeFiles/grbc.dir/src/file.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/target_exe.cc.o -MF CMakeFiles/grbc.dir/src/target_exe.cc.o.d -o CMakeFiles/grbc.dir/src/target_exe.cc.o -c /home/interfiber/dev/grbc/src/target_exe.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/target_exe.cc.o -MF CMakeFiles/grbc.dir/src/target_exe.cc.o.d -o CMakeFiles/grbc.dir/src/target_exe.cc.o -c /home/interfiber/dev/grbc/src/target_exe.cc", "file": "/home/interfiber/dev/grbc/src/target_exe.cc", "output": "CMakeFiles/grbc.dir/src/target_exe.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/platform.cc.o -MF CMakeFiles/grbc.dir/src/platform.cc.o.d -o CMakeFiles/grbc.dir/src/platform.cc.o -c /home/interfiber/dev/grbc/src/platform.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/platform.cc.o -MF CMakeFiles/grbc.dir/src/platform.cc.o.d -o CMakeFiles/grbc.dir/src/platform.cc.o -c /home/interfiber/dev/grbc/src/platform.cc", "file": "/home/interfiber/dev/grbc/src/platform.cc", "output": "CMakeFiles/grbc.dir/src/platform.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/ninja.cc.o -MF CMakeFiles/grbc.dir/src/ninja.cc.o.d -o CMakeFiles/grbc.dir/src/ninja.cc.o -c /home/interfiber/dev/grbc/src/ninja.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/ninja.cc.o -MF CMakeFiles/grbc.dir/src/ninja.cc.o.d -o CMakeFiles/grbc.dir/src/ninja.cc.o -c /home/interfiber/dev/grbc/src/ninja.cc", "file": "/home/interfiber/dev/grbc/src/ninja.cc", "output": "CMakeFiles/grbc.dir/src/ninja.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -g -MD -MT CMakeFiles/grbc.dir/src/generator.cc.o -MF CMakeFiles/grbc.dir/src/generator.cc.o.d -o CMakeFiles/grbc.dir/src/generator.cc.o -c /home/interfiber/dev/grbc/src/generator.cc", + "command": "/usr/lib64/ccache/g++ -I/home/interfiber/dev/grbc/include -isystem /home/interfiber/dev/grbc/vendor/sol2/include -O2 -g -DNDEBUG -MD -MT CMakeFiles/grbc.dir/src/generator.cc.o -MF CMakeFiles/grbc.dir/src/generator.cc.o.d -o CMakeFiles/grbc.dir/src/generator.cc.o -c /home/interfiber/dev/grbc/src/generator.cc", "file": "/home/interfiber/dev/grbc/src/generator.cc", "output": "CMakeFiles/grbc.dir/src/generator.cc.o" }, { "directory": "/home/interfiber/dev/grbc/build", - "command": ": && /usr/lib64/ccache/g++ -g CMakeFiles/grbc.dir/src/main.cc.o CMakeFiles/grbc.dir/src/utils.cc.o CMakeFiles/grbc.dir/src/file.cc.o CMakeFiles/grbc.dir/src/target_exe.cc.o CMakeFiles/grbc.dir/src/platform.cc.o CMakeFiles/grbc.dir/src/ninja.cc.o CMakeFiles/grbc.dir/src/generator.cc.o -o grbc -llua && :", + "command": ": && /usr/lib64/ccache/g++ -O2 -g -DNDEBUG CMakeFiles/grbc.dir/src/main.cc.o CMakeFiles/grbc.dir/src/utils.cc.o CMakeFiles/grbc.dir/src/file.cc.o CMakeFiles/grbc.dir/src/target_exe.cc.o CMakeFiles/grbc.dir/src/platform.cc.o CMakeFiles/grbc.dir/src/ninja.cc.o CMakeFiles/grbc.dir/src/generator.cc.o -o grbc -llua && :", "file": "CMakeFiles/grbc.dir/src/main.cc.o", "output": "grbc" }, diff --git a/include/grbc/ext.h b/include/grbc/ext.h new file mode 100644 index 0000000..918821d --- /dev/null +++ b/include/grbc/ext.h @@ -0,0 +1,3 @@ +#pragma once + +#define GRBC_EXT_pkg_config_NAME "GRBC_EXT_pkg_config" \ No newline at end of file diff --git a/include/grbc/generator.h b/include/grbc/generator.h index df89be7..56aa727 100644 --- a/include/grbc/generator.h +++ b/include/grbc/generator.h @@ -3,6 +3,12 @@ #include #include +enum GeneratorTargetType { + GeneratorTargetType_Executable, + GeneratorTargetType_SharedLibrary, + GeneratorTargetType_StaticLibrary +}; + struct GeneratorResult { std::string file_name; std::string content; @@ -17,17 +23,18 @@ struct GeneratorCompileCommand { std::string compiler_flags; }; -struct GeneratorLinkExecutableCommand { +struct GeneratorLinkTargetCommand { std::vector object_files; - - std::string output_exe; - std::string linker_flags; + + std::string output_name; + + GeneratorTargetType target_type; }; struct GeneratorTarget { std::vector compile_commands; - std::vector link_executable_commands; + std::vector link_target_commands; }; typedef GeneratorResult (*Generator_Run)(); diff --git a/include/grbc/ninja.h b/include/grbc/ninja.h index 569aad2..ed03cec 100644 --- a/include/grbc/ninja.h +++ b/include/grbc/ninja.h @@ -22,6 +22,11 @@ std::string ninja_build_rule_link_cxx(); */ std::string ninja_build_rule_link_cc(); +/** + * Generate the build rule for archiving object files into a shared library + */ +std::string ninja_build_rule_archive_library(); + /** * Generate a line which builds the given file */ @@ -34,7 +39,13 @@ ninja_build_rule_compile_file(const GeneratorCompileCommand &compile_cmd); std::string ninja_build_default_variables(); /** - * Generate a line which links the given file + * Generate a line which links the given file to an executable */ -std::string ninja_build_rule_link_exe_target( - const GeneratorLinkExecutableCommand &link_cmd); \ No newline at end of file +std::string +ninja_build_rule_link_exe_target(const GeneratorLinkTargetCommand &link_cmd); + +/** + * Generate a line which links the given file to a library + */ +std::string +ninja_build_rule_link_lib_target(const GeneratorLinkTargetCommand &link_cmd); diff --git a/include/grbc/spec.h b/include/grbc/spec.h index 4031e92..53eae61 100644 --- a/include/grbc/spec.h +++ b/include/grbc/spec.h @@ -1,11 +1,13 @@ #pragma once #include +#include #include #include #define GRBC_VERSION "1.0" enum LanguageType { LanguageType_CPP, LanguageType_C }; +enum LibraryType { LibraryType_Shared, LibraryType_Static }; struct TargetInfo { /// Name of the target @@ -19,6 +21,8 @@ struct Package { linker_flags = table.get("linker_flags"); } + Package() = default; + std::string name; std::string compiler_flags; @@ -27,6 +31,16 @@ struct Package { }; struct PackageConfig { + PackageConfig(const sol::table &table) { + name = table.get("name"); + libraries = table.get>("libraries"); + include_dirs = table.get>("include_dirs"); + compile_flags = table.get>("compile_flags"); + linker_flags = table.get>("linker_flags"); + } + + PackageConfig() = default; + std::string name; std::vector libraries; @@ -50,21 +64,21 @@ struct GlobalConfig { /// Build directory std::string build_dir = "build"; - /// System that we are targetting - PlatformType target; - - /// Path to the target.hcfg - std::string target_config; + /// Path to the platform.hcfg, in_memory if not on-disk + std::string platform_config; }; struct ExecutableConfig { ExecutableConfig(const sol::table &table) { name = table.get("name"); files = table.get>("files"); + requirements = table.get>("requirements"); compile_flags = table.get>("compile_flags"); + linker_flags = table.get>("linker_flags"); + include_dirs = table.get>("include_dirs"); language_type = table.get("language_type"); @@ -77,19 +91,67 @@ struct ExecutableConfig { LanguageType language_type; /// List of files to compile - std::vector files; + std::vector files{}; /// Requirments of the executable - std::vector requirements; + std::vector requirements{}; /// Compiler flags - std::vector compile_flags; + std::vector compile_flags{}; /// Linker flags - std::vector linker_flags; + std::vector linker_flags{}; /// Include directories - std::vector include_dirs; + std::vector include_dirs{}; +}; + +struct LibraryConfig { + LibraryConfig(const sol::table &table) { + name = table.get("name"); + files = table.get>("files"); + + requirements = table.get>("requirements"); + + compile_flags = table.get>("compile_flags"); + + linker_flags = table.get>("linker_flags"); + + include_dirs = table.get>("include_dirs"); + + language_type = table.get("language_type"); + lib_type = table.get("lib_type"); + + if (!table["package_config"].is()) + package_config = table.get("package_config"); + } + + /// Name of the executable + std::string name; + + /// Type of language + LanguageType language_type; + + /// Type of library + LibraryType lib_type; + + /// Package config + PackageConfig package_config{}; + + /// List of files to compile + std::vector files{}; + + /// Requirments of the executable + std::vector requirements{}; + + /// Compiler flags + std::vector compile_flags{}; + + /// Linker flags + std::vector linker_flags{}; + + /// Include directories + std::vector include_dirs{}; }; struct Platform { @@ -115,12 +177,14 @@ void grbc_want_version(const std::string &version); void grbc_exception(const std::string &exception_string); -GlobalConfig grbc_get_config(); +GlobalConfig& grbc_get_config(); std::string grbc_file(const std::string &file_path); TargetInfo grbc_executable(const ExecutableConfig &executable_config); +TargetInfo grbc_library(const LibraryConfig &library_config); + void grbc_load_platform(const std::string &file_path); void grbc_set_platform(const Platform &platform); @@ -147,4 +211,13 @@ PlatformType grbc_get_platform(); bool grbc_is_64bit(); -bool grbc_is_32bit(); \ No newline at end of file +bool grbc_is_32bit(); + +std::string grbc_compiler_define(const std::string &define, + const std::string &value); + +std::string grbc_get_lib_extension(LibraryType lib_type); + +Package grbc_bake_package_config(const PackageConfig &config); + +Package grbc_pkg(const std::string &package_name); \ No newline at end of file diff --git a/include/grbc/state.h b/include/grbc/state.h index fd16637..35654d4 100644 --- a/include/grbc/state.h +++ b/include/grbc/state.h @@ -2,15 +2,18 @@ #include "grbc/generator.h" #include "grbc/spec.h" #include +#include +#include struct GState { Platform current_platform; sol::state lua; std::vector targets; - std::vector generators; + std::unordered_map packages; + std::string ninja_output; static GState& get() { diff --git a/spec/datatypes.md b/spec/datatypes.md index c30a363..4e9a563 100644 --- a/spec/datatypes.md +++ b/spec/datatypes.md @@ -46,6 +46,9 @@ struct LibraryConfig { /// Type of library LibraryType lib_type; + /// Package config for the library, leave empty to disable + PackageConfig package_config{}; + /// Requirments of the library Array requirements; @@ -125,8 +128,8 @@ struct GlobalConfig { /// Platform to target (pulled from the target config) PlatformTarget target; - /// Path to the target.hcfg - path target_config; + /// Path to the platform.hcfg, in_memory if not on-disk + string platform_config; }; ``` @@ -151,6 +154,9 @@ struct Platform { /// C compiler string cc_compiler; + /// Do these compilers produce 32bit code? + bool is_64bit; + /// Type of the platform PlatformType platform_type; }; @@ -162,4 +168,14 @@ enum LanguageType { LanguageType_CPP, LanguageType_C }; +``` + +## Profile +```c++ +struct Profile { + string name; + + Array compiler_flags; + Array linker_flags; +}; ``` \ No newline at end of file diff --git a/spec/functions.md b/spec/functions.md index dc10e9a..e8505a4 100644 --- a/spec/functions.md +++ b/spec/functions.md @@ -2,7 +2,7 @@ See [datatypes.md](./datatypes.md) for data types/structures ## [X] grbc_get_config() -> GlobalConfig -Get the config +Get the config as as read-write reference ## [X] grbc_want_version(version: String) -> Void Assure grbc is running on ```version``` @@ -28,11 +28,11 @@ Check if we are targeting a 32bit system ## [X] grbc_executable(executable_config: ExecutableConfig) -> TargetInfo Create a new executable and add it to the build list -## grbc_library(library_config: LibraryConfig) -> TargetInfo +## [X] grbc_library(library_config: LibraryConfig) -> TargetInfo Create a new library and add it to the build list -## [X] grbc_create_package(package_config: PackageConfig) -> Package -Create a new package +## grbc_pkg(package_name: String) -> Package +Get a package with the given name and return its baked form ## [X] grbc_file(file_path: String) -> Path Used when listing source files, should perform pre-checks on the file and return its path @@ -68,4 +68,13 @@ Convert the given file path to an object file path Replace substring in string with replacement ## [X] grbc_include_dirs_to_cflags(include_dirs: Array) -> String -Generate compiler flags to include the given directories \ No newline at end of file +Generate compiler flags to include the given directories + +## [X] grbc_compiler_define(define: String, value: String) -> String +Generate a compiler flag to define a variable + +## [X] grbc_get_lib_extension(library_type: LibraryType) -> String +Get the given extension for a library file on the current platform + +## [X] grbc_bake_package_config(config: PackageConfig) -> Package +Convert a PackageConfig into a Package \ No newline at end of file diff --git a/src/main.cc b/src/main.cc index 6e50158..4f784d3 100644 --- a/src/main.cc +++ b/src/main.cc @@ -20,7 +20,7 @@ int main() { // PackageConfig lua.new_usertype( - "PackageConfig", "name", &PackageConfig::name, "libraries", + "PackageConfig", sol::constructors(), "name", &PackageConfig::name, "libraries", &PackageConfig::libraries, "include_dirs", &PackageConfig::include_dirs, "compile_flags", &PackageConfig::compile_flags, "linker_flags", &PackageConfig::linker_flags); @@ -28,36 +28,51 @@ int main() { // GlobalConfig lua.new_usertype( "GlobalConfig", "engine_version", &GlobalConfig::engine_version, - "architecture", &GlobalConfig::architecture, "target", - &GlobalConfig::target, "target_config", &GlobalConfig::target_config); + "architecture", &GlobalConfig::architecture, "target_config", &GlobalConfig::platform_config); // Platform lua.new_usertype("Platform", "name", &Platform::name, "cxx_compiler", &Platform::cxx_compiler, "cc_compiler", &Platform::cc_compiler, - "platform_type", &Platform::platform_type, "is_64bit", &Platform::is_64bit); + "platform_type", &Platform::platform_type, + "is_64bit", &Platform::is_64bit); // PlatformType lua.new_enum("PlatformType", {{"Win32", PlatformType_Win32}, {"Linux", PlatformType_Linux}}); // LanguageType - lua.new_enum("LanguageType", { - { "Cpp", LanguageType_CPP }, - { "C", LanguageType_C } - }); + lua.new_enum( + "LanguageType", {{"Cpp", LanguageType_CPP}, {"C", LanguageType_C}}); + + // LibraryType + lua.new_enum("LibraryType", {{"Static", LibraryType_Static}, + {"Shared", LibraryType_Shared}}); // ExecutableConfig lua.new_usertype( "ExecutableConfig", sol::constructors(), "name", &ExecutableConfig::name, "files", &ExecutableConfig::files, - "requirments", &ExecutableConfig::requirements, "compile_flags", + "requirements", &ExecutableConfig::requirements, "compile_flags", &ExecutableConfig::compile_flags, "linker_flags", &ExecutableConfig::linker_flags, "include_dirs", - &ExecutableConfig::include_dirs, "language_type", &ExecutableConfig::language_type); + &ExecutableConfig::include_dirs, "language_type", + &ExecutableConfig::language_type); + + // LibraryConfig + lua.new_usertype( + "LibraryConfig", sol::constructors(), "name", + &LibraryConfig::name, "files", &LibraryConfig::files, "requirements", + &LibraryConfig::requirements, "compile_flags", + &LibraryConfig::compile_flags, "linker_flags", + &LibraryConfig::linker_flags, "include_dirs", + &LibraryConfig::include_dirs, "language_type", + &LibraryConfig::language_type, "lib_type", &LibraryConfig::lib_type, + "package_config", &LibraryConfig::package_config); // Package - lua.new_usertype("Package", sol::constructors(), "name", &Package::name, "compiler_flags", + lua.new_usertype("Package", sol::constructors(), + "name", &Package::name, "compiler_flags", &Package::compiler_flags, "linker_flags", &Package::linker_flags); @@ -66,6 +81,7 @@ int main() { lua.set("grbc_get_config", grbc_get_config); lua.set("grbc_file", grbc_file); lua.set("grbc_executable", grbc_executable); + lua.set("grbc_library", grbc_library); lua.set("grbc_load_platform", grbc_load_platform); lua.set("grbc_set_platform", grbc_set_platform); lua.set("grbc_find_compiler", grbc_find_compiler); @@ -79,13 +95,15 @@ int main() { lua.set("grbc_is_linux", grbc_is_linux); lua.set("grbc_is_win32", grbc_is_win32); lua.set("grbc_get_platform", grbc_get_platform); + lua.set("grbc_compiler_define", grbc_compiler_define); + lua.set("grbc_get_lib_extension", grbc_get_lib_extension); + lua.set("grbc_bake_package_config", grbc_bake_package_config); + lua.set("grbc_pkg", grbc_pkg); // Load generators - - GState::get().generators.push_back({ - .name = "ninja", - .func = ninja_generator - }); + + GState::get().generators.push_back( + {.name = "ninja", .func = ninja_generator}); log_msg("loading HConfig..."); diff --git a/src/ninja.cc b/src/ninja.cc index ff87618..431e79b 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -40,7 +40,7 @@ std::string ninja_build_rule_link_cxx() { std::string result = "## build_rule_link_cxx ##\n\n"; result += "rule link_cxx\n"; result += " command = $cxx_path $p_cflags -o $out $in $p_linker_flags\n"; - result += " description = Linking C++ executables $out\n\n"; + result += " description = Linking C++ target $out\n\n"; return result; } @@ -49,7 +49,16 @@ std::string ninja_build_rule_link_cc() { std::string result = "## build_rule_link_cc ##\n\n"; result += "rule link_cc\n"; result += " command = $cc_path $p_cflags -o $out $in $p_linker_flags\n"; - result += " description = Linking C executables $out\n\n"; + result += " description = Linking C target $out\n\n"; + + return result; +} + +std::string ninja_build_rule_archive_library() { + std::string result = "## build_rule_archive_library ##\n\n"; + result += "rule archive\n"; + result += " command = rm -f $out; ar crs $out $in\n"; + result += " description = Creating static library $out\n\n"; return result; } @@ -79,9 +88,9 @@ std::string ninja_build_default_variables() { return result; } -std::string ninja_build_rule_link_exe_target( - const GeneratorLinkExecutableCommand &link_cmd) { - std::string result = "## Link: " + link_cmd.output_exe + " ##\n\n"; +std::string +ninja_build_rule_link_lib_target(const GeneratorLinkTargetCommand &link_cmd) { + std::string result = "## Link: " + link_cmd.output_name + " ##\n\n"; std::string file_list; @@ -91,7 +100,34 @@ std::string ninja_build_rule_link_exe_target( file_list.pop_back(); - result += "build " + link_cmd.output_exe + ": link_cxx " + file_list + "\n"; + if (link_cmd.target_type == GeneratorTargetType_SharedLibrary) { + result += "build $builddir/" + link_cmd.output_name + ": link_cxx " + + file_list + "\n"; + + result += " p_linker_flags = " + link_cmd.linker_flags + " -shared\n"; + result += " p_cflags = \n\n"; + } else { + result += "build $builddir/" + link_cmd.output_name + ": archive " + + file_list + "\n\n"; + } + + return result; +} + +std::string +ninja_build_rule_link_exe_target(const GeneratorLinkTargetCommand &link_cmd) { + std::string result = "## Link: " + link_cmd.output_name + " ##\n\n"; + + std::string file_list; + + for (auto &file : link_cmd.object_files) { + file_list += "$builddir/" + file + " "; + } + + file_list.pop_back(); + + result += "build $builddir/" + link_cmd.output_name + ": link_cxx " + + file_list + "\n"; result += " p_linker_flags = " + link_cmd.linker_flags + "\n"; result += " p_cflags = \n\n"; @@ -113,14 +149,19 @@ GeneratorResult ninja_generator() { result.content += ninja_build_rule_compile_cxx(); result.content += ninja_build_rule_link_cc(); result.content += ninja_build_rule_link_cxx(); + result.content += ninja_build_rule_archive_library(); for (auto &target : GState::get().targets) { for (auto &compile_cmd : target.compile_commands) { result.content += ninja_build_rule_compile_file(compile_cmd); } - for (auto &link_cmd : target.link_executable_commands) { - result.content += ninja_build_rule_link_exe_target(link_cmd); + for (auto &link_cmd : target.link_target_commands) { + if (link_cmd.target_type == GeneratorTargetType_Executable) { + result.content += ninja_build_rule_link_exe_target(link_cmd); + } else { + result.content += ninja_build_rule_link_lib_target(link_cmd); + } } } diff --git a/src/package.cc b/src/package.cc new file mode 100644 index 0000000..a2ebcab --- /dev/null +++ b/src/package.cc @@ -0,0 +1,42 @@ +#include "grbc/spec.h" +#include "grbc/state.h" + +Package grbc_pkg(const std::string &package_name) { + for (auto &pkg : GState::get().packages) { + if (pkg.first == package_name) return pkg.second; + } + + grbc_exception("Could not find package with name '" + package_name + "'"); + + return Package{}; +} + +Package grbc_bake_package_config(const PackageConfig &config) { + Package pkg{}; + pkg.name = config.name; + + // Generate list of compiler + linker arguments + + for (auto &subpkg : config.libraries) { + pkg.compiler_flags += subpkg.compiler_flags + " "; + pkg.linker_flags += subpkg.linker_flags + " "; + } + + for (auto &linker_flag : config.linker_flags) { + pkg.linker_flags += linker_flag + " "; + } + + for (auto &compiler_flag : config.compile_flags) { + pkg.compiler_flags += compiler_flag + " "; + } + + // Remove trailing whitespace + + if (pkg.compiler_flags.back() == ' ') + pkg.compiler_flags.pop_back(); + + if (pkg.linker_flags.back() == ' ') + pkg.linker_flags.pop_back(); + + return pkg; +} \ No newline at end of file diff --git a/src/platform.cc b/src/platform.cc index ee01ec3..732a34b 100644 --- a/src/platform.cc +++ b/src/platform.cc @@ -21,12 +21,16 @@ void grbc_set_platform(const Platform &platform) { log_msg(("C++ compiler = " + platform.cxx_compiler).c_str()); log_msg(("C compiler = " + platform.cc_compiler).c_str()); + + grbc_get_config().platform_config = "in_memory"; } void grbc_load_platform(const std::string &file_path) { Platform platform = GState::get().lua.script_file(file_path); grbc_set_platform(platform); + + grbc_get_config().platform_config = file_path; } std::string grbc_find_compiler(const std::string &compiler_name) { diff --git a/src/target_exe.cc b/src/target_exe.cc index 117ae9b..3d87bfb 100644 --- a/src/target_exe.cc +++ b/src/target_exe.cc @@ -3,55 +3,60 @@ #include "grbc/state.h" TargetInfo grbc_executable(const ExecutableConfig &executable_config) { - TargetInfo target_config{}; + TargetInfo target_config{}; - std::string exe_name = executable_config.name; - std::string compiler_args; - std::string linker_args; + std::string exe_name = executable_config.name; - for (auto &package : executable_config.requirements) { - compiler_args += package.compiler_flags + " "; - linker_args += package.linker_flags + " "; - } + if (grbc_is_win32()) + exe_name += ".exe"; - for (auto &linker_arg : executable_config.linker_flags) { - linker_args += linker_arg + " "; - } + std::string compiler_args; + std::string linker_args; - for (auto &compiler_arg : executable_config.compile_flags) { - compiler_args += compiler_arg + " "; - } + for (auto &package : executable_config.requirements) { + compiler_args += package.compiler_flags + " "; + linker_args += package.linker_flags + " "; + } - // Include directories + for (auto &linker_arg : executable_config.linker_flags) { + linker_args += linker_arg + " "; + } - compiler_args += grbc_include_dirs_to_cflags(executable_config.include_dirs); + for (auto &compiler_arg : executable_config.compile_flags) { + compiler_args += compiler_arg + " "; + } - GeneratorTarget target{}; + // Include directories - std::vector object_files; + compiler_args += grbc_include_dirs_to_cflags(executable_config.include_dirs); - for (auto &src_file : executable_config.files) { - GeneratorCompileCommand compile_cmd{}; - compile_cmd.source_file = src_file; - compile_cmd.object_file = grbc_object_file(src_file); - compile_cmd.compiler_flags = compiler_args; - compile_cmd.language_type = executable_config.language_type; + GeneratorTarget target{}; - object_files.push_back(compile_cmd.object_file); + std::vector object_files; - target.compile_commands.push_back(compile_cmd); - } + for (auto &src_file : executable_config.files) { + GeneratorCompileCommand compile_cmd{}; + compile_cmd.source_file = src_file; + compile_cmd.object_file = grbc_object_file(src_file); + compile_cmd.compiler_flags = compiler_args; + compile_cmd.language_type = executable_config.language_type; - // Final executable link + object_files.push_back(compile_cmd.object_file); - GeneratorLinkExecutableCommand executable_link_cmd{}; - executable_link_cmd.linker_flags = linker_args; - executable_link_cmd.object_files = object_files; - executable_link_cmd.output_exe = exe_name; + target.compile_commands.push_back(compile_cmd); + } - target.link_executable_commands.push_back(executable_link_cmd); + // Final executable link - GState::get().targets.push_back(target); + GeneratorLinkTargetCommand executable_link_cmd{}; + executable_link_cmd.linker_flags = linker_args; + executable_link_cmd.object_files = object_files; + executable_link_cmd.output_name = exe_name; + executable_link_cmd.target_type = GeneratorTargetType_Executable; - return target_config; + target.link_target_commands.push_back(executable_link_cmd); + + GState::get().targets.push_back(target); + + return target_config; } \ No newline at end of file diff --git a/src/target_lib.cc b/src/target_lib.cc new file mode 100644 index 0000000..e7123ed --- /dev/null +++ b/src/target_lib.cc @@ -0,0 +1,81 @@ +#include "grbc/generator.h" +#include "grbc/spec.h" +#include "grbc/state.h" + +TargetInfo grbc_library(const LibraryConfig &library_config) { + TargetInfo target_config{}; + + std::string lib_name = library_config.name; + lib_name += grbc_get_lib_extension(library_config.lib_type); + + std::string compiler_args; + std::string linker_args; + + for (auto &package : library_config.requirements) { + compiler_args += package.compiler_flags + " "; + linker_args += package.linker_flags + " "; + } + + for (auto &linker_arg : library_config.linker_flags) { + linker_args += linker_arg + " "; + } + + for (auto &compiler_arg : library_config.compile_flags) { + compiler_args += compiler_arg + " "; + } + + // Include directories + + compiler_args += grbc_include_dirs_to_cflags(library_config.include_dirs); + + GeneratorTarget target{}; + + std::vector object_files; + + for (auto &src_file : library_config.files) { + GeneratorCompileCommand compile_cmd{}; + compile_cmd.source_file = src_file; + compile_cmd.object_file = grbc_object_file(src_file); + compile_cmd.compiler_flags = compiler_args; + compile_cmd.language_type = library_config.language_type; + + object_files.push_back(compile_cmd.object_file); + + target.compile_commands.push_back(compile_cmd); + } + + // Generate package config + PackageConfig pkg_cfg{}; + pkg_cfg.name = library_config.name; + pkg_cfg.libraries = library_config.package_config.libraries; + pkg_cfg.include_dirs = library_config.include_dirs; + + if (library_config.lib_type == LibraryType_Static) { + pkg_cfg.linker_flags.push_back(grbc_get_config().build_dir + "/" + lib_name); + } + + // FIXME: Shared library linker flags + + if (!pkg_cfg.name.empty()) { + GState::get().packages.insert( + {pkg_cfg.name, grbc_bake_package_config(pkg_cfg)}); + } + + GeneratorLinkTargetCommand link_target{}; + + if (library_config.lib_type == LibraryType_Shared) { + link_target.target_type = GeneratorTargetType_SharedLibrary; + } else { + link_target.target_type = GeneratorTargetType_StaticLibrary; + } + + link_target.object_files = object_files; + link_target.linker_flags = linker_args; + link_target.output_name = lib_name; + + target.link_target_commands.push_back(link_target); + + GState::get().targets.push_back(target); + + return target_config; +} \ No newline at end of file diff --git a/src/utils.cc b/src/utils.cc index 387edc1..6a11830 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -1,5 +1,6 @@ #include "grbc/helpers.h" #include "grbc/spec.h" +#include "grbc/state.h" #include #include #include @@ -20,15 +21,15 @@ void grbc_want_version(const std::string &version) { } std::string grbc_object_file(const std::string &file_path) { - std::filesystem::path path(file_path); - path.replace_extension(".o"); + std::filesystem::path path(file_path); + path.replace_extension(".o"); - std::string path_str = path.generic_string(); + std::string path_str = path.generic_string(); - // Strip out stuff - std::string no_spaces = grbc_replace_string(path_str, ' ', '_'); + // Strip out stuff + std::string no_spaces = grbc_replace_string(path_str, ' ', '_'); - return no_spaces; + return no_spaces; } std::string grbc_replace_string(const std::string &string, char substring, @@ -47,15 +48,19 @@ std::string grbc_replace_string(const std::string &string, char substring, return res; } -GlobalConfig grbc_get_config() { +GlobalConfig& grbc_get_config() { static GlobalConfig cfg{}; return cfg; } -std::string grbc_include_dirs_to_cflags(const std::vector &include_dirs) { +std::string +grbc_include_dirs_to_cflags(const std::vector &include_dirs) { + if (include_dirs.empty()) + return ""; + std::string result; - + for (auto &include_dir : include_dirs) { result += "-I" + include_dir + " "; } @@ -65,6 +70,31 @@ std::string grbc_include_dirs_to_cflags(const std::vector &include_ return result; } -void grbc_log(const std::string &message) { - log_msg(message.c_str()); +void grbc_log(const std::string &message) { log_msg(message.c_str()); } + +std::string grbc_compiler_define(const std::string &define, + const std::string &value) { + return "-D" + define + "=" + value; +} + +std::string grbc_get_lib_extension(LibraryType lib_type) { + PlatformType platform_type = GState::get().current_platform.platform_type; + + if (platform_type == PlatformType_Linux && lib_type == LibraryType_Shared) { + return ".so"; + } else if (platform_type == PlatformType_Linux && + lib_type == LibraryType_Static) { + return ".a"; + } else if (platform_type == PlatformType_Win32 && + lib_type == LibraryType_Shared) { + return ".dll"; + } else if (platform_type == PlatformType_Win32 && + lib_type == LibraryType_Static) { + return ".lib"; + } + + grbc_exception("Could not determine library extension for current platform + " + "library combo"); + + return ""; } \ No newline at end of file