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);