X-Git-Url: http://git.nguyen.vg/gitweb/?p=tatoo.git;a=blobdiff_plain;f=remake.cpp;h=de68c4dc53c7d5b299a35dce41e631c16803aa72;hp=b8387be2b0230e44382f322657cdf4875c00df94;hb=836d6ea0aebf1f947faa74db1d78168afb882930;hpb=5bdd670738e0af306581819ef41659f961a0df12 diff --git a/remake.cpp b/remake.cpp index b8387be..de68c4d 100644 --- a/remake.cpp +++ b/remake.cpp @@ -343,7 +343,7 @@ https://github.com/apenwarr/redo for an implementation and some comprehensive do \section sec-licensing Licensing @author Guillaume Melquiond -@version 0.9 +@version 0.10 @date 2012-2013 @copyright This program is free software: you can redistribute it and/or modify @@ -373,8 +373,8 @@ When building a target, the following sequence of events happens: - #start calls #find_rule (and #find_generic_rule) to get the rule. - It then creates a pseudo-client if the rule has static dependencies, or - calls #run_script otherwise. In both cases, a new job is created and its - targets are put into #job_targets. + calls #run_script otherwise. In both cases, a new job is created; the + rule and the variables are stored into #jobs. - #run_script creates a shell process and stores it in #job_pids. It increases #running_jobs. - The child process possibly calls remake with a list of targets. @@ -392,7 +392,7 @@ When building a target, the following sequence of events happens: - When a child process ends, #server_loop calls #finalize_job, which removes the process from #job_pids, decreases #running_jobs, and calls #complete_job. -- #complete_job removes the job from #job_targets and calls #update_status +- #complete_job removes the job from #jobs and calls #update_status to change the status of the targets. It also removes the target files in case of failure. */ @@ -668,7 +668,7 @@ static int waiting_jobs = 0; /** * Global counter used to produce increasing job numbers. - * @see job_targets + * @see jobs */ static int job_counter = 0; @@ -719,6 +719,11 @@ static std::string working_dir; */ static std::string prefix_dir; +/** + * Whether the prefix directory is different from #working_dir. + */ +static bool changed_prefix_dir; + /** * Whether target-specific variables are propagated to prerequisites. */ @@ -870,7 +875,16 @@ static void init_prefix_dir() struct stat s; if (stat((prefix_dir + "/Remakefile").c_str(), &s) == 0) { - chdir(prefix_dir.c_str()); + if (!changed_prefix_dir) return; + if (chdir(prefix_dir.c_str())) + { + perror("Failed to change working directory"); + exit(EXIT_FAILURE); + } + if (show_targets) + { + std::cout << "remake: Entering directory `" << prefix_dir << '\'' << std::endl; + } return; } size_t pos = prefix_dir.find_last_of('/'); @@ -880,6 +894,7 @@ static void init_prefix_dir() exit(EXIT_FAILURE); } prefix_dir.erase(pos); + changed_prefix_dir = true; } } @@ -1076,44 +1091,44 @@ static int expect_token(std::istream &in, int mask) /** * Read a (possibly quoted) word. */ -static std::string read_word(std::istream &in) +static std::string read_word(std::istream &in, bool detect_equal = true) { - int c = in.get(); + int c = in.peek(); std::string res; if (!in.good()) return res; - char const *separators = " \t\r\n:$(),=+\""; + char const *separators = " \t\r\n$(),:"; bool quoted = c == '"'; - if (!quoted) - { - if (strchr(separators, c)) - { - in.putback(c); - return res; - } - res += c; - } + if (quoted) in.ignore(1); + bool plus = false; while (true) { - c = in.get(); + c = in.peek(); if (!in.good()) return res; if (quoted) { + in.ignore(1); if (c == '\\') res += in.get(); else if (c == '"') - return res; + quoted = false; else res += c; + continue; } - else + if (detect_equal && c == '=') { - if (strchr(separators, c)) - { - in.putback(c); - return res; - } - res += c; + if (plus) in.putback('+'); + return res; } + if (plus) + { + res += '+'; + plus = false; + } + if (strchr(separators, c)) return res; + in.ignore(1); + if (detect_equal && c == '+') plus = true; + else res += c; } } @@ -1218,11 +1233,11 @@ input_status input_generator::next(std::string &res) switch (expect_token(in, Word | Dollarpar)) { case Word: - res = read_word(in); + res = read_word(in, false); return Success; case Dollarpar: { - std::string name = read_word(in); + std::string name = read_word(in, false); if (name.empty()) return SyntaxError; if (expect_token(in, Rightpar)) nested = new variable_generator(name, local_variables); @@ -2021,21 +2036,23 @@ static bool still_need_rebuild(std::string const &target) */ static void complete_job(int job_id, bool success) { - DEBUG_open << "Completing job " << job_id << "... "; + DEBUG << "Completing job " << job_id << '\n'; job_map::iterator i = jobs.find(job_id); assert(i != jobs.end()); string_list const &targets = i->second.rule.targets; if (success) { + if (show_targets) std::cout << "Finished"; for (string_list::const_iterator j = targets.begin(), j_end = targets.end(); j != j_end; ++j) { update_status(*j); + if (show_targets) std::cout << ' ' << *j; } + if (show_targets) std::cout << std::endl; } else { - DEBUG_close << "failed\n"; std::cerr << "Failed to build"; for (string_list::const_iterator j = targets.begin(), j_end = targets.end(); j != j_end; ++j) @@ -2137,25 +2154,17 @@ static std::string prepare_script(job_t const &job) */ static status_e run_script(int job_id, job_t const &job) { - if (show_targets) - { - std::cout << "Building"; - for (string_list::const_iterator i = job.rule.targets.begin(), - i_end = job.rule.targets.end(); i != i_end; ++i) - { - std::cout << ' ' << *i; - } - std::cout << std::endl; - } - ref_ptr dep; dep->targets = job.rule.targets; dep->deps.insert(job.rule.deps.begin(), job.rule.deps.end()); + if (show_targets) std::cout << "Building"; for (string_list::const_iterator i = job.rule.targets.begin(), i_end = job.rule.targets.end(); i != i_end; ++i) { dependencies[*i] = dep; + if (show_targets) std::cout << ' ' << *i; } + if (show_targets) std::cout << std::endl; std::string script = prepare_script(job); @@ -2792,6 +2801,10 @@ static void server_mode(std::string const &remakefile, string_list const &target free(socket_name); #endif save_dependencies(); + if (show_targets && changed_prefix_dir) + { + std::cout << "remake: Leaving directory `" << prefix_dir << '\'' << std::endl; + } exit(build_failure ? EXIT_FAILURE : EXIT_SUCCESS); } @@ -2927,8 +2940,6 @@ static void usage(int exit_status) */ int main(int argc, char *argv[]) { - init_working_dir(); - std::string remakefile; string_list targets; bool literal_targets = false; @@ -2973,11 +2984,14 @@ int main(int argc, char *argv[]) continue; } new_target: - targets.push_back(normalize(arg, working_dir, working_dir)); + targets.push_back(arg); DEBUG << "New target: " << arg << '\n'; } } + init_working_dir(); + normalize_list(targets, working_dir, working_dir); + if (indirect_targets) { load_dependencies(std::cin);