diff --git a/scripts/common.mak b/scripts/common.mak index 0325296..ea06da2 100644 --- a/scripts/common.mak +++ b/scripts/common.mak @@ -1,35 +1,19 @@ -export lsproj = $(bin)/lsproj$(exe) +export lsdep = $(bin)/lsdep$(exe) export lsinc = $(bin)/lsinc$(exe) export flags += "-I$(inc)" -D$(OS) -DPPC_VERSION_MAJOR=$(version-major) -DPPC_VERSION_MINOR=$(version-minor) -DPPC_VERSION_BUILD=$(version-build) -$(shell make -f scripts/ls.mak lsinc=$(lsinc) lsproj=$(lsproj) src=$(src) "flags=$(flags)" all) +$(shell make -f scripts/ls.mak lsinc=$(lsinc) lsdep=$(lsdep) src=$(src) "flags=$(flags)" all) rwildcard=$(foreach d, $(wildcard $(1:=/*)),\ $(call rwildcard,$d,$2)\ $(filter $(subst *,%,$2),$d)\ ) -uniq=$(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) -modoutput=$(shell ./$(lsproj) $(src) $1 output) -deps=$(strip \ - $(foreach dep, $(shell ./$(lsproj) $(src) $1 deps),\ - $(if $(wildcard src/$(dep)), $(dep),\ - $(error The module '$(dep)' (dependency of '$1') doesn't exist)\ - )\ - )\ -) -rdeps=$(call uniq,$(strip \ - $(foreach dep, $(call deps,$1),\ - $(call rdeps,$(dep))\ - $(dep)\ - )\ -)) +deps=$(shell $(lsdep) --dir=deps $1) +rdeps=$(shell $(lsdep) --dir=deps --rec $1) -fdeps=$(foreach dep,$(call deps,$1),$(bin)/lib$(lib)$(call modoutput,$(dep))$(so)) -frdeps=$(foreach dep,$(call rdeps,$1),$(bin)/lib$(lib)$(call modoutput,$(dep))$(so)) - -ldeps=$(foreach dep,$(call deps,$1),-l$(lib)$(call modoutput,$(dep))) -lrdeps=$(foreach dep,$(call rdeps,$1),-l$(lib)$(call modoutput,$(dep))) +frdeps=$(shell $(lsdep) --dir=deps --rec --transform=$(bin)/lib$(lib)*$(so) $1) +ldeps=$(shell $(lsdep) --dir=deps --transform=-l$(lib) $1) modules = $(patsubst $(src)/%/,$(bin)/lib$(lib)%$(so),$(filter-out $(src)/$(mainmodule)/,$(wildcard $(src)/*/))) sources = $(call rwildcard,$(src)/$1,*.cc) diff --git a/scripts/ls.mak b/scripts/ls.mak index 0d4e125..c6316fa 100644 --- a/scripts/ls.mak +++ b/scripts/ls.mak @@ -1,9 +1,11 @@ -all: $(lsproj) $(lsinc) +all: $(lsdep) $(lsinc) -$(lsproj): $(src)/lsproj.cc +$(lsdep): $(src)/lsdep.cc $(call mkdir,$(dir $@)) + echo - Compiling lsdep.cc... >&2 $(CXX) $(flags) $^ -o $@ $(lsinc): $(src)/lsinc.cc + echo - Compiling lsinc.cc... >&2 $(call mkdir,$(dir $@)) $(CXX) $(flags) $^ -o $@ \ No newline at end of file diff --git a/src/lang.proj b/src/lang.proj deleted file mode 100644 index 3151a2d..0000000 --- a/src/lang.proj +++ /dev/null @@ -1,2 +0,0 @@ -lang -utils \ No newline at end of file diff --git a/src/lsdep.cc b/src/lsdep.cc new file mode 100644 index 0000000..167dd30 --- /dev/null +++ b/src/lsdep.cc @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace std::string_literals; +using std::size_t; +namespace fs = std::filesystem; + +fs::path proj_dir; +bool recursive = false; +std::string prefix = "", suffix = ""; + +static inline void ltrim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { + return !std::isspace(ch); + })); +} +static inline void rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { + return !std::isspace(ch); + }).base(), s.end()); +} +static inline void trim(std::string &s) { + rtrim(s); + ltrim(s); +} +static bool read_line(std::istream &str, std::string &res) { + if (str.eof()) return false; + std::getline(str, res); + trim(res); + return true; +} + +void read_project_rec(const std::string &name, std::set &res, bool rec = false) { + static std::set prev; + + if (!prev.emplace(name).second) throw name + ": Circular dependency detected."; + + std::ifstream f(proj_dir / name); + std::string line; + + while (read_line(f, line)) { + if (line.find('#') != std::string::npos) { + line = line.substr(0, line.find('#')); + } + + trim(line); + + if (line.size() == 0) continue; + if (line == name) throw name + ": Depends on itself."; + + res.emplace(line); + if (rec) read_project_rec(line, res); + } + + prev.erase(name); +} + +void print_err(const std::string &error, const std::string &context) { + std::cerr << context << ": " << error; +} + +void set_transform(const std::string &val) { + size_t i = 0; + bool last_percent = false; + bool is_prefix = true; + prefix = "", suffix = ""; + + for (; i < val.length(); i++) { + if (is_prefix) { + if (val[i] == '*') { + if (last_percent) { + last_percent = false; + } + else { + last_percent = true; + continue; + } + } + else if (last_percent) { + is_prefix = false; + last_percent = false; + } + } + + if (is_prefix) prefix += val[i]; + else suffix += val[i]; + } +} + +bool process_arg(std::string arg) { + if (arg.find("--") != 0) return false; + arg = arg.substr(2); + + if (arg == "rec") { + recursive = true; + return true; + } + else if (arg.find("transform=") == 0) { + arg = arg.substr(10); + set_transform(arg); + } + else if (arg.find("dir=") == 0) { + arg = arg.substr(4); + proj_dir = arg; + } + else { + throw "Incorrect usage. Syntax: [--rec] [--transform=prefix%suffix] [--dir=dir] [projects...]"s; + } + return true; +} + +int main(int argc, const char *argv[]) { + try { + argc--; + argv++; + + std::set deps; + + while (argc > 0 && process_arg(argv[0])) { + argc--; + argv++; + } + while (argc > 0) { + // if (recursive) read_project_rec(argv[0], deps); + // else read_project(argv[0], deps); + read_project_rec(argv[0], deps, recursive); + argc--; + argv++; + } + + for (auto &dep : deps) { + std::cout << prefix + dep + suffix << std::endl; + } + + return 0; + } + catch (std::string err) { + std::cerr << "error: lsdep: " << err << std::endl; + } + return -1; +} diff --git a/src/lsinc.cc b/src/lsinc.cc index b1e82cf..003a3ea 100644 --- a/src/lsinc.cc +++ b/src/lsinc.cc @@ -108,7 +108,7 @@ int main(int argc, char **argv) { return 0; } catch (std::string err) { - std::cerr << "Error: " << err << std::endl; + std::cerr << "error: lsinc: " << err << std::endl; } return -1; diff --git a/src/lsproj.cc b/src/lsproj.cc deleted file mode 100644 index 7579810..0000000 --- a/src/lsproj.cc +++ /dev/null @@ -1,138 +0,0 @@ -#include -#include -#include -#include - -using namespace std::string_literals; - -struct project_t { - std::string output; - std::vector deps; -}; - -std::string read_str(std::istream &f, const std::string &skip_chars, const std::string &end_chars, int &end_char) { - std::vector res {}; - int c; - - while (true) { - c = f.get(); - auto a = end_chars.find(c); - if (c == -1 || a != std::string::npos) { - end_char = c; - return ""; - } - if ((a = skip_chars.find(c)) == std::string::npos) { - f.unget(); - break; - } - } - - while (true) { - c = f.get(); - if (c == -1 || end_chars.find(c) != std::string::npos) { - end_char = c; - break; - } - - res.push_back(c); - } - while (true) { - if (skip_chars.find(res.back()) != std::string::npos) res.pop_back(); - else break; - } - - return std::string { res.begin(), res.end() }; -} -std::string read_str(std::istream &f, const std::string &skip_chars, const std::string &end_chars) { - int end_char; - return read_str(f, skip_chars, end_chars, end_char); -} - -project_t read_project(std::istream &f) { - int end_ch; - std::string name = read_str(f, " \v\t\r\n", "\n", end_ch); - std::vector deps {}; - - if (name.length() == 0) { - throw "The name of a project may not be empty."s; - } - - if (end_ch == -1) { - return project_t { - .output = name, - .deps = deps, - }; - } - - if (name.find(',') != std::string::npos || name.find(' ') != std::string::npos) { - throw "The name of a project may not contain spaces or commas."s; - } - - while (true) { - std::string dep = read_str(f, " \v\t\r\n", ",\n", end_ch); - - if (dep.find(' ') != std::string::npos) { - throw "The name of a dependency may not contain spaces."s; - } - - if (dep.length()) { - deps.push_back(dep); - if (end_ch == '\n') break; - } - if (end_ch == -1) break; - } - - return project_t { - .output = name, - .deps = deps, - }; -} - -void print_err(const std::string &error, const std::string &context) { - std::cerr << context << ": " << error; -} - -int main(int argc, const char *argv[]) { - std::string proj_name = ""; - try { - argc--; - argv++; - - if (argc != 3) { - throw "Incorrect usage. Syntax: [src-dir] [project-name] [output|deps]."s; - } - - std::string proj_path = (std::string) argv[0] + "/" + argv[1] + ".proj"; - proj_name = argv[1]; - - std::ifstream f { proj_path, std::ios_base::in }; - - if (!f.is_open()) { - throw "The project '"s + argv[1] + "' doesn't exist."s; - } - - project_t project = read_project(f); - f.close(); - - if ((std::string) argv[2] == "output") { - std::cout << project.output; - } - else if ((std::string) argv[2] == "deps") { - for (std::string dep : project.deps) { - std::cout << dep << " "; - } - } - else { - throw "Invalid command given. Available commands: output, deps."s; - } - - std::cout << std::endl; - - return 0; - } - catch (std::string err) { - if (proj_name.length()) std::cerr << "Error: " << proj_name << ": " << err << std::endl; - else std::cerr << "Error: " << err << std::endl; - } - return -1; -} diff --git a/src/main.proj b/src/main.proj deleted file mode 100644 index 3b14ac7..0000000 --- a/src/main.proj +++ /dev/null @@ -1,2 +0,0 @@ -main -utils, treeifier, lang \ No newline at end of file diff --git a/src/treeifier.proj b/src/treeifier.proj deleted file mode 100644 index d34bf8b..0000000 --- a/src/treeifier.proj +++ /dev/null @@ -1,2 +0,0 @@ -treeifier -utils, lang \ No newline at end of file diff --git a/src/utils.proj b/src/utils.proj deleted file mode 100644 index 6625243..0000000 --- a/src/utils.proj +++ /dev/null @@ -1 +0,0 @@ -utils \ No newline at end of file