\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
- #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 <b>remake</b> with a list of targets.
- 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.
*/
/**
* Global counter used to produce increasing job numbers.
- * @see job_targets
+ * @see jobs
*/
static int job_counter = 0;
static std::string prefix_dir;
/**
- * Whether target-specific variables are propagated to prerequisites.
+ * Whether the prefix directory is different from #working_dir.
*/
-static bool propagate_vars = false;
-
+static bool changed_prefix_dir;
/**
- * Whether to print that we changed working directory (to be nice with emacs)
+ * Whether target-specific variables are propagated to prerequisites.
*/
-static bool print_change_working_dir = false;
+static bool propagate_vars = false;
#ifndef WINDOWS
static volatile sig_atomic_t got_SIGCHLD = 0;
*/
static void init_prefix_dir()
{
- std::string old_prefix_dir = prefix_dir;
for (;;)
{
struct stat s;
if (stat((prefix_dir + "/Remakefile").c_str(), &s) == 0)
{
- if (0 == chdir(prefix_dir.c_str()))
+ if (!changed_prefix_dir) return;
+ if (chdir(prefix_dir.c_str()))
{
- if (old_prefix_dir != prefix_dir)
- {
- std::cout << "remake: Entering directory `"
- << prefix_dir << "'"
- << std::endl;
- print_change_working_dir = true;
- }
- return;
+ perror("Failed to change working directory");
+ exit(EXIT_FAILURE);
}
- else
+ if (show_targets)
{
- std::cerr << "Cannot change working directory to '" << prefix_dir << "'";
- exit(EXIT_FAILURE);
+ std::cout << "remake: Entering directory `" << prefix_dir << '\'' << std::endl;
}
+ return;
}
size_t pos = prefix_dir.find_last_of('/');
if (pos == std::string::npos)
exit(EXIT_FAILURE);
}
prefix_dir.erase(pos);
+ changed_prefix_dir = true;
}
}
/**
* 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;
}
}
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);
*/
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)
*/
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<dependency_t> 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);
if (sigaction(SIGINT, &sa, NULL) == -1) goto error;
// Prepare a named unix socket in temporary directory.
- struct stat tmpstat;
- char * tmpdir;
- if ((0 == stat(tmpdir = getenv("TMPDIR"), &tmpstat)
- && (S_ISDIR(tmpstat.st_mode)))
- || ((0 == stat(tmpdir = (char*)P_tmpdir, &tmpstat))
- && (S_ISDIR(tmpstat.st_mode)))
- || ((0 == stat(tmpdir = (char*)"/tmp", &tmpstat))
- && (S_ISDIR(tmpstat.st_mode))));
- else goto error;
- std::stringstream tmpname;
- long int rnd = now ^ getpid();
- do
- {
- srandom(rnd);
- rnd = random();
- tmpname << tmpdir << "/rmk-";
- tmpname.fill('0');
- tmpname.width(8);
- tmpname << rnd;
- }
- while (access (tmpname.str().c_str(), F_OK) == 0);
- socket_name = strdup(tmpname.str().c_str());
+ socket_name = tempnam(NULL, "rmk-");
if (!socket_name) goto error2;
struct sockaddr_un socket_addr;
size_t len = strlen(socket_name);
free(socket_name);
#endif
save_dependencies();
- if (print_change_working_dir)
- std::cout << "remake: Leaving directory `" << prefix_dir
- << "'" <<std::endl;
+ if (show_targets && changed_prefix_dir)
+ {
+ std::cout << "remake: Leaving directory `" << prefix_dir << '\'' << std::endl;
+ }
exit(build_failure ? EXIT_FAILURE : EXIT_SUCCESS);
}
*/
int main(int argc, char *argv[])
{
- init_working_dir();
-
std::string remakefile;
string_list targets;
bool literal_targets = false;
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);