diff --git a/.gitignore b/.gitignore index 889a8e7..8a7df3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ main obj/ rl/ -raylib/ \ No newline at end of file +raylib/ +build \ No newline at end of file diff --git a/build.cpp b/build.cpp new file mode 100644 index 0000000..c1dcfb6 --- /dev/null +++ b/build.cpp @@ -0,0 +1,147 @@ +#include "build.hpp" + +std::filesystem::path OBJ_DIR = "obj"; +std::filesystem::path INC_DIR = "inc"; +std::filesystem::path SRC_DIR = "src"; +std::filesystem::path RAYLIB_DIR = "raylib"; +std::filesystem::path BUILD_FILE = "main"; + +bool web_build = false; + +std::string cpp_compiler = "g++"; +std::string c_compiler = "gcc"; +std::string opt_flags = "-ggdb"; +std::vector command; +std::vector RAYINCLUDE = {"-Iraylib/src", "-Iraylib/src/external/glfw/include", "-Iraylib/src/external/glfw/deps/mingw"}; + +void compile_raylib_dir() +{ + std::filesystem::path out_dir = OBJ_DIR / RAYLIB_DIR; + std::filesystem::path ray_src_dir = RAYLIB_DIR / "src"; + std::filesystem::create_directory(out_dir); + std::vector ray_srcs = {"rcore.c", "rshapes.c", "rtextures.c", "rtext.c", "utils.c", "rmodels.c", "raudio.c"}; + std::vector ray_flags = {"-DPLATFORM_WEB", "-DGRAPHICS_API_OPENGL_ES2"}; + + if (!web_build) + { + ray_srcs.push_back("rglfw.c"); + ray_flags = {"-D_GNU_SOURCE", "-DPLATFORM_DESKTOP", "-DGRAPHICS_API_OPENGL_33"}; + } + + command.clear(); + command.push_back(c_compiler); + command.push_back("-c"); + command.push_back(""); + command.push_back("-o"); + command.push_back(""); + + command.insert(command.end(), ray_flags.begin(), ray_flags.end()); + command.push_back(opt_flags); + command.insert(command.end(), RAYINCLUDE.begin(), RAYINCLUDE.end()); + + std::filesystem::path out, src; + + for (size_t i = 0; i < ray_srcs.size(); i++) + { + src = ray_src_dir / ray_srcs[i]; + out = out_dir / ray_srcs[i].replace_extension(".o"); + if (check_if_rebuild(src, out)) + { + command[2] = src.c_str(); + command[4] = out.c_str(); + nob_cmd_run_sync(command); + } + } +} + +bool compile_src_dir() +{ + nob_directory src_dir = get_all_files_in_dir(SRC_DIR); + nob_directory obj_dir; + + for (auto &&i : src_dir.files) + { + std::filesystem::path tmp = i; + obj_dir.files.push_back(OBJ_DIR / tmp.replace_extension(".o")); + } + + for (auto &&i : src_dir.dirs) + { + obj_dir.dirs.push_back(OBJ_DIR / i); + } + + for (auto &&i : obj_dir.dirs) + { + std::filesystem::create_directory(i); + } + + command.clear(); + command.push_back(cpp_compiler); + command.push_back("-c"); + command.push_back(""); + command.push_back("-o"); + command.push_back(""); + command.push_back(opt_flags); + command.insert(command.end(), RAYINCLUDE.begin(), RAYINCLUDE.end()); + command.push_back("-Iinc"); + + command.push_back("-std=c++23"); + command.push_back("-Wall"); + command.push_back("-Werror"); + bool build = false; + for (size_t i = 0; i < src_dir.files.size(); i++) + { + if (check_if_rebuild(src_dir.files[i], obj_dir.files[i])) + { + command[2] = src_dir.files[i]; + command[4] = obj_dir.files[i]; + if (!nob_cmd_run_sync(command)) + return false; + + build = true; + } + } + return build; +} + +void compile_obj_dir() +{ + nob_directory obj_dir = get_all_files_in_dir(OBJ_DIR); + + command.clear(); + command.push_back(cpp_compiler); + + for (auto &&i : obj_dir.files) + { + command.push_back(i); + } + + command.push_back("-o"); + command.push_back(BUILD_FILE); + nob_cmd_run_sync(command); +} + +int main(int argc, char const *argv[]) +{ + if (rebuild_my_self(__FILE__, argv[0])) + return 0; + + std::filesystem::create_directory(OBJ_DIR); + + if (!std::filesystem::is_directory(RAYLIB_DIR)) + { + command = {"git", "clone", "--depth", "1", "--branch", "5.0", "git@github.com:raysan5/raylib.git"}; + nob_cmd_run_sync(command); + } + if (!std::filesystem::is_directory(RAYLIB_DIR)) + return 0; + compile_raylib_dir(); + + if (compile_src_dir()) + compile_obj_dir(); + + command = {"./main"}; + nob_cmd_run_sync(command); + + return 0; +} diff --git a/build.hpp b/build.hpp new file mode 100644 index 0000000..23865ae --- /dev/null +++ b/build.hpp @@ -0,0 +1,165 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +void print_command(std::vector &arguments) +{ + for (auto &&i : arguments) + { + printf("%s ", i.c_str()); + } + printf("\n"); +} + +int nob_cmd_run_async(std::vector &arguments) +{ + std::vector argument_list; + for (const auto &arg : arguments) + { + argument_list.push_back(const_cast(arg.c_str())); + } + argument_list.push_back(NULL); + + pid_t cpid = fork(); + if (cpid < 0) + { + printf("Could not fork child process: %s\n", strerror(errno)); + return -1; + } + + if (cpid == 0) + { + if (execvp(argument_list[0], argument_list.data()) < 0) + { + print_command(arguments); + printf("Could not exec child process: %s\n", strerror(errno)); + exit(1); + } + assert(0 && "unreachable"); + } + + return cpid; +} + +bool nob_proc_wait(int proc) +{ + if (proc == -1) + return false; + + for (;;) + { + int wstatus = 0; + if (waitpid(proc, &wstatus, 0) < 0) + { + printf("could not wait on command (pid %d): %s\n", proc, strerror(errno)); + return false; + } + + if (WIFEXITED(wstatus)) + { + int exit_status = WEXITSTATUS(wstatus); + if (exit_status != 0) + { + printf("command exited with exit code %d\n", exit_status); + return false; + } + break; + } + + if (WIFSIGNALED(wstatus)) + { + printf("command process was terminated by %s\n", strsignal(WTERMSIG(wstatus))); + return false; + } + } + + return true; +} + +bool nob_cmd_run_sync(std::vector &arguments) +{ + print_command(arguments); + int p = nob_cmd_run_async(arguments); + if (p == -1) + return false; + return nob_proc_wait(p); +} + +bool check_if_rebuild(std::filesystem::path &org_path, std::filesystem::path &new_path) +{ + struct stat file_stat_one; + if (stat(org_path.c_str(), &file_stat_one)) + return false; + + struct stat file_stat_two; + if (stat(new_path.c_str(), &file_stat_two)) + return true; + + return file_stat_one.st_ctime > file_stat_two.st_ctime; +} + +bool rebuild_my_self(std::filesystem::path src_path, std::filesystem::path exec_path) +{ + if (!check_if_rebuild(src_path, exec_path)) + return false; + + std::vector comand = {"g++", src_path, "-o", exec_path, "-g"}; + if (!nob_cmd_run_sync(comand)) + return false; + + comand = {exec_path}; + if (!nob_cmd_run_sync(comand)) + return false; + + printf("rebuild\n"); + return true; +} + +struct nob_directory +{ + std::vector files; + std::vector dirs; +}; + +nob_directory get_all_files_in_dir(std::filesystem::path directory_path) +{ + namespace fs = std::filesystem; + + nob_directory dir; + if (!fs::is_directory(directory_path)) + return dir; + + std::list dirs; + dirs.push_back(directory_path); + dir.dirs.push_back(directory_path); + + while (!dirs.empty()) + { + for (const auto &entry : fs::directory_iterator(dirs.front())) + { + // Check if the entry is a regular file + if (fs::is_regular_file(entry)) + { + dir.files.push_back(entry.path()); + } + // Check if the entry is a directory + else if (fs::is_directory(entry)) + { + dirs.push_back(entry.path()); + dir.dirs.push_back(entry.path()); + } + } + dirs.pop_front(); + } + + return dir; +}