From 4e6ca79e757a95488354f5c451b8f434c3bb092a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B5=D0=B2=20=D0=93=D1=80?= =?UTF-8?q?=D0=B8=D0=B3=D0=BE=D1=80=D0=B8=D0=B9?= Date: Fri, 16 Aug 2024 22:22:27 +0300 Subject: [PATCH] Moved from pkg-config to my lofi replica of csv --- .gitignore | 2 +- README.txt | 29 +++++++++--- install.sh | 58 ++++++++++++++++------- regexis024_build_system.h | 96 ++++++++++++++++++++++++-------------- regexis024_build_system.sh | 36 ++++++++++++++ 5 files changed, 161 insertions(+), 60 deletions(-) create mode 100755 regexis024_build_system.sh diff --git a/.gitignore b/.gitignore index 1737b2d..5b753d7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ # Never use CMAKE in production CMakeLists.txt cmake-build-debug/ - +m.cpp \ No newline at end of file diff --git a/README.txt b/README.txt index 6351a3a..31ebb62 100644 --- a/README.txt +++ b/README.txt @@ -2,18 +2,33 @@ Build system for libregexis024 ABOUT -This is a build system in a form of header-only C++ library. It supports generation and installation of pkg-config files for your project. +This build system installs only two files: +1) header regexis024_build_system.h, that contains some useful functions for writing build scripts in C++ +2) script regexis024_build_system.sh, that compiles a build script in your project (script invokes g++ with +-I flag pointing to regexis024_build_system.h installation dir) INSTALLATION -You don't need to compile anything, this is a header-only library (more precisely, it is an only-one-file-kind library) +You don't need to compile anything, this is a header-only library -./install.sh [header installation path] [pkg-config file path] +./install.sh [installation root] -[header installation path] defaults to /usr/include -[pkg-config file path] defaults to /usr/lib/pkgconfig/regexis024-build-system.h +[installation root] by default is /usr +Files will be installed to +./include/regexis024_build_system.h and +./bin/regexis024_build_system.sh HISTORY -One day I realized that make is a complete garbage, cmake is even worse, and shell scripting language is too hard to use to write anything complex. -I had to invent my own build system for my project libregexis024. But regexis024_build_system can be used for any other C++ project just fine. +One day I realized that make is a complete garbage, cmake is even worse, and shell scripting language is too hard to use +to write anything complex. +I had to invent my own build system for my project libregexis024. But regexis024_build_system can be used for any other +C++ project just fine. +Some time ago this build system was able to generate pkg-config .pc files for built libraries, but +for some reason pkg-config shuffled cflags on my friends pc, so I moved from pkg-config to my own, much simpler +library flags description format: +* For both cflags and linkage flags do this: +** For each argument do this: +*** escape " and \ symbols in argument and "tighten" result into double-quotes (a"\" c -> "a\"\\\" c") +** Concatenate results +* Join results by ; diff --git a/install.sh b/install.sh index df05753..4f1aafe 100755 --- a/install.sh +++ b/install.sh @@ -1,32 +1,58 @@ #!/bin/sh H_FILE="regexis024_build_system.h" +SH_TEMP_FILE="regexis024_build_system.sh" -if [ \! \( -f "$H_FILE" \) ]; then echo "Change cwd to root of build system source code root directory"; exit 1; fi +if [ \! \( -f "$H_FILE" \) -o \! \( -f "$SH_TEMP_FILE" \) ]; then + echo "Change cwd to root of build system source code root directory"; exit 1; +fi usage(){ - echo "Usage: ./install.sh [header installation dir path] [pkg-config file installation path]" + echo "Usage: ./install.sh [installation root]" } -if [ $# -gt 2 ]; then usage; exit 1; fi +if [ $# -gt 1 ]; then usage; exit 1; fi -H_INST_DIR="/usr/include" -PC_INST_FILE="/usr/lib/pkgconfig/regexis024-build-system.pc" +INST_ROOT="/usr" -if [ $# -ge 1 ]; then H_INST_DIR="$1"; fi -if [ $# -ge 2 ]; then PC_INST_FILE="$2"; fi +if [ $# -ge 1 ]; then INST_ROOT="$1"; fi -cp "$H_FILE" "$H_INST_DIR/$H_FILE" +INST_ROOT="$(realpath "$INST_ROOT")" -if [ $? != 0 ]; then echo "Can't install"; exit 1; fi +install -d "$INST_ROOT/include" -echo "Name: regexis024-build-system" > "$PC_INST_FILE" -echo "Description: Cool C++ build system" >> "$PC_INST_FILE" -echo "Version: 1.0" >> "$PC_INST_FILE" +if [ $? != 0 ]; then + echo "Can't install IR/bin directory"; exit 1; +fi -COOL_FLAGS="-Wall -pedantic -Wno-unused-variable -Wno-unused-but-set-variable -Werror=return-type -Wno-reorder" -COOL_FLAGS="$COOL_FLAGS -D _GLIBCXX_DEBUG -D _POSIX_C_SOURCE=200809L" -COOL_FLAGS="$COOL_FLAGS -g --std c++14" +install "$H_FILE" "$INST_ROOT/include/" -echo "Cflags: $COOL_FLAGS -I $H_INST_DIR" >> "$PC_INST_FILE" +if [ $? != 0 ]; then + echo "Can't copy $H_FILE"; exit 1; +fi + +I_DIR="$INST_ROOT/include" + +escape4shell(){ + echo "$1" | sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/" +} + +SH_TEMPLATE="$(cat "$SH_TEMP_FILE")" +SH_TEMPLATE="${SH_TEMPLATE/"i_dir=99999"/"id_dir=$(escape4shell "$I_DIR")"}" + +install -d "$INST_ROOT/bin" + +if [ $? != 0 ]; then echo "Failed to install IR/bin directory"; exit 1; fi + +echo "$SH_TEMPLATE" > "$INST_ROOT/bin/$SH_TEMP_FILE" + +if [ $? != 0 ]; then + echo "Can't paste generated $SH_TEMP_FILE"; exit 1 +fi + +chmod +x "$INST_ROOT/bin/$SH_TEMP_FILE" + +if [ $? != 0 ]; then + echo "Can't chmod +x on .sh script in IR/bin"; exit 1 +fi diff --git a/regexis024_build_system.h b/regexis024_build_system.h index 43f49b1..7e09652 100644 --- a/regexis024_build_system.h +++ b/regexis024_build_system.h @@ -703,6 +703,51 @@ struct ExternalLibraryData { std::vector linkage_flags; }; +std::string lib_connection_flags_to_passed_forward_str(const ExternalLibraryData& lib) { + std::string result; + for (const std::string& f: lib.compilation_flags) + result += escape_with_doublequoting(f); + result += ";"; + for (const std::string& f: lib.linkage_flags) + result += escape_with_doublequoting(f); + return result; +} + +ExternalLibraryData parse_passed_forward_str(const std::string& str) { + ExternalLibraryData result; + int f = 0; + auto getOut = [&]() -> std::vector& { + return f > 0 ? result.linkage_flags : result.compilation_flags; + }; + bool in_str = false; + bool bsl = false; + for (char ch: str) { + if (in_str) { + if (bsl) { + bsl = false; + getOut().back() += ch; + } else if (ch == '\\') { + bsl = true; + } else if (ch == '"') { + in_str = false; + } else { + getOut().back() += ch; + } + } else if (ch == '"') { + in_str = true; + getOut().emplace_back(); + } else if (ch == ';') { + f++; + if (f > 1) + THROW("PASSED_FORWARD.txt has only two fields: first - cflags; second - linking flags"); + } else { + ASSERT(ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n', + "Only whitespaces can be between arguments in PASSED_FORWARD.txt") + } + } + return result; +} + struct ExternalLibraryTarget { std::string name; ExternalLibraryData data; @@ -727,9 +772,6 @@ struct CTarget { std::vector exported_headers; std::string installation_dir; - /* If empty, no .pc file will be created. Otherwise, must include filename */ - std::string pc_output_path; - std::string version = "0.1"; }; void check_is_good_name_1(const std::string& name) { @@ -741,7 +783,7 @@ void check_is_good_name_1(const std::string& name) { void check_target_name(const std::string& name) { check_is_good_name_1(name); - ASSERT(name != "obj", "DON'T YOU NEVER EVER CALL YOUR TARGET obj") + ASSERT(name != "obj" && name != "PASSED_FORWARD.txt", "DON'T YOU NEVER EVER CALL YOUR TARGET like this") } void check_is_clean_path_1(const path_t& path) { @@ -764,11 +806,6 @@ void check_c_unit_name(const path_t& P) { ASSERT(P.parts.back().substr(ld) == ".cpp", "Right now only c++ is supported"); } -void check_pkg_conf_rel_install_path(const path_t& P) { - ASSERT_pl(P.is_relative && !P.parts.empty()); - ASSERT_pl(does_str_end_in(P.parts.back(), ".pc")); -} - /* Argument `name` is just a name in `units` array, return value is relative to $IR/$TARGET_NAME/obj */ path_t c_unit_name_to_obj_filename(const std::string& PtoC) { path_t P(PtoC); @@ -786,10 +823,6 @@ path_t c_unit_name_to_obj_filename(const std::string& PtoC) { return P; } -path_t c_unit_name_to_source_filename(const std::string& PtoC){ - return path_t(PtoC); -} - void load_ctargets_on_building_and_installing( const std::vector& ext_lib_targs, const std::vector& proj_targs, @@ -799,8 +832,7 @@ void load_ctargets_on_building_and_installing( const std::string& proj_compiled_dir_path, const std::string& install_include_dir_path, const std::string& install_lib_dir_path, - const std::string& install_bin_dir_path, - const std::string& install_pkgconfig_dir_path) + const std::string& install_bin_dir_path) { std::map ext_libs_map; for (auto& e: ext_lib_targs) { @@ -813,7 +845,7 @@ void load_ctargets_on_building_and_installing( size_t end_BBU_id; /* Main build unit of target in "install" runlevel */ size_t end_IBU_id; - /* When this ctarget is used as dependency, these flags should be used aquire my ctarget as dependency */ + /* When this ctarget is used as dependency, these flags should be used to aquire my ctarget as dependency */ std::vector emitted_compilation_flags_USED_HERE; std::vector emitted_compilation_flags_PASSED_FORWARD; std::vector emitted_linkage_flags_USED_HERE; @@ -843,13 +875,13 @@ void load_ctargets_on_building_and_installing( size_t mk_personal_targ_dir_bu_id = add_bbu(new MkdirBuildUnit(path_t(proj_compiled_dir_path) / tg.name)); std::vector all_comp_units_bu_ids; auto BU_to_SOURCE_FILEPATH = [&](const std::string& bu) -> path_t { - return path_t(proj_src_dir_path) / c_unit_name_to_source_filename(bu); + return path_t(proj_src_dir_path) / bu; }; auto BU_to_OBJ_FILEPATH = [&](const std::string& bu) -> path_t { return path_t(proj_compiled_dir_path) / tg.name / "obj" / c_unit_name_to_obj_filename(bu); }; auto generate_cu_BUs = [&](const std::vector& ctg_type_intrinsic_comp_args) { - const std::string comp_cmd = "g++"; // todo: think of some other way around + const std::string comp_cmd = "g++"; // todo: *speaks in soydev voice* AAAA OOOO AAA I LOVE GCC for (const std::string& bu: tg.units) { check_c_unit_name(bu); path_t buDir = bu; @@ -944,7 +976,6 @@ void load_ctargets_on_building_and_installing( if (tg.type == "executable") { ASSERT(tg.exported_headers.empty(), "C-target's field `exported_headers` is unsupported for type `executable`"); ASSERT(tg.include_ir.empty(), "C-target's field `include_ir` is unsupported for type `executable`"); - ASSERT(tg.pc_output_path.empty(), "C-target's field `pc_output_path` is unsupported for type `executable`"); generate_cu_BUs({}); generate_targ_link_BU({}, ""); gen_ibus_for_this_th(install_bin_dir_path, ""); @@ -987,19 +1018,13 @@ void load_ctargets_on_building_and_installing( "-Wl,-rpath," + install_lib_dir_path + "/" + tg.installation_dir, "-l:" + tg.name + ".so" }); - /* Determining how to create pkg-config file at installation stage */ - if (!tg.pc_output_path.empty()) { - check_pkg_conf_rel_install_path(tg.pc_output_path); - // todo: ESCAPE THESE VALUES - size_t pkg_conf_install_ibu = add_ibu(new FileWriteBuildUnit( - path_t(install_pkgconfig_dir_path) / tg.pc_output_path, - "Name: " + tg.name + "\n" + - "Description: \n" + - "Version: " + tg.version + "\n" + - "Cflags: " + join_string_arr(s.emitted_compilation_flags_PASSED_FORWARD, " ") + "\n" + - "Libs: " + join_string_arr(s.emitted_linkage_flags_PASSED_FORWARD, " ") + "\n")); - ret_at_install[blank_ibu_for_tg_FINAL]->bu_dependencies.push_back(pkg_conf_install_ibu); - } + size_t PASSED_FORWARD_file_ibu = add_ibu(new FileWriteBuildUnit( + path_t(proj_compiled_dir_path) / tg.name / "PASSED_FORWARD.txt", + lib_connection_flags_to_passed_forward_str(ExternalLibraryData{ + s.emitted_compilation_flags_PASSED_FORWARD, + s.emitted_linkage_flags_PASSED_FORWARD + }))); + ret_at_install[blank_ibu_for_tg_FINAL]->bu_dependencies.push_back(PASSED_FORWARD_file_ibu); /* s.end_BU... fields allow us to establish dependency relations between BUs of ctargets with such relation */ s.end_BBU_id = targ_FINAL_bbu_id; s.end_IBU_id = blank_ibu_for_tg_FINAL; @@ -1061,7 +1086,6 @@ const char* default_PR_postf_built_compiled = "/built/compiled"; const char* default_IR_postf_include = "/include"; const char* default_IR_postf_lib = "/lib"; const char* default_IR_postf_bin = "/bin"; -const char* default_IR_postf_pkgconfig = "/lib/pkgconfig"; void regular_bs_cli_cmd_interpret(const std::vector& args, NormalCBuildSystemCommandMeaning& reta) { normal_c_build_system_command_interpret(args, reta, default_PR_postf_built_local_install); @@ -1078,9 +1102,9 @@ void regular_ctargets_to_2bus_conversion( project_root + default_PR_postf_built_compiled, installation_root + default_IR_postf_include, installation_root + default_IR_postf_lib, - installation_root + default_IR_postf_bin, - installation_root + default_IR_postf_pkgconfig + installation_root + default_IR_postf_bin ); } -#endif //REGEXIS024_BUILD_SYSTEM_H +#endif + diff --git a/regexis024_build_system.sh b/regexis024_build_system.sh new file mode 100755 index 0000000..0083fc3 --- /dev/null +++ b/regexis024_build_system.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +i_dir=99999 + +flags="-Wall -Wextra -pedantic -Wno-unused-variable -Wno-unused-but-set-variable -Werror=return-type -Wno-reorder -Wno-missing-field-initializers" +flags="$flags -g --std c++14 -D _GLIBCXX_DEBUG" + +usage(){ + echo "Usage: regexis024_build_system.sh [bs script (cpp file)]" +} + +if [ $# -gt 1 ]; then usage; exit 1; fi + +SCRIPT="./building/main.cpp" + +is_cpp(){ + case "$1" in *.cpp) true;; *) false;; esac; +} + +if [ $# -ge 1 ]; then + SCRIPT="$1" +fi + +if [ \! \( -f "$SCRIPT" \) ]; then + echo "No such file $SCRIPT"; exit 1; +fi + +if ! is_cpp "$SCRIPT"; then + echo "Script file does not end in .cpp"; exit 1 +fi + +# Todo: rewrite with sed +COMPILED="${SCRIPT%.cpp}" + +g++ $flags -I "$i_dir" -o "$COMPILED" "$SCRIPT" +