Skip to content

Commit

Permalink
Forward flags to sub processes.
Browse files Browse the repository at this point in the history
When ninja invokes ninja (for instance when building a sub-project) it
is useful to have a way to control the flags used by the sub-ninja
process. If I pass '-d explain' or '-v' when starting
ninja from the command line on the top project, I expect these flags
to be forwarded to the sub-ninja process.

Note that this patch has limited parsing capabilities of the
NINJA_FLAGS environment variables but that should be enough for our
use case.

Fixes ninja-build#797, ninja-build#922 and ninja-build#816.
  • Loading branch information
nicolasdespres committed Dec 20, 2015
1 parent 9a4eb58 commit 0634f90
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 2 deletions.
62 changes: 60 additions & 2 deletions src/ninja.cc
Expand Up @@ -993,7 +993,6 @@ int ExceptionFilter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
/// Returns an exit code, or -1 if Ninja should continue.
int ReadFlags(int* argc, char*** argv,
Options* options, BuildConfig* config) {
config->parallelism = GuessParallelism();

enum { OPT_VERSION = 1 };
const option kLongOptions[] = {
Expand Down Expand Up @@ -1075,6 +1074,59 @@ int ReadFlags(int* argc, char*** argv,
return -1;
}

const char* kNINJA_FLAGS = "NINJA_FLAGS";

int ReadFlagsFromEnv(Options* options, BuildConfig* config) {
char* flags = getenv(kNINJA_FLAGS);
if (flags == NULL)
return -1;

int argc = 1;
enum { MAX_ARGC = 1014 };
char* argv[MAX_ARGC];
argv[0] = "ninja-from-env";

char* flags_str = strdup(flags);
SplitArgv(flags_str, &argc, argv, MAX_ARGC);

int rc;
{
char** argv_addr = argv;
rc = ReadFlags(&argc, &argv_addr, options, config);
optind = 1;
}

free(flags_str);
return rc;
}

void PublishFlagsToEnv(const Options& options, const BuildConfig& config) {
enum { BUFLEN = 1014 };
char buf[BUFLEN];

snprintf(buf, BUFLEN, "-j %d -k %d -l %f",
config.parallelism,
config.failures_allowed,
config.max_load_average);
if (config.verbosity)
strcat(buf, " -v");
if (config.dry_run)
strcat(buf, " -n");
if (options.dupe_edges_should_err)
strcat(buf, " -w dupbuild=err");
else
strcat(buf, " -w dupbuild=warn");
if (g_metrics != NULL)
strcat(buf, " -d stats");
else if (g_explaining)
strcat(buf, " -d explain");
else if (g_keep_rsp)
strcat(buf, " -d keeprsp");
else if (g_experimental_statcache)
strcat(buf, " -d nostatcache");
setenv(kNINJA_FLAGS, buf, 1);
}

int real_main(int argc, char** argv) {
BuildConfig config;
Options options = {};
Expand All @@ -1083,9 +1135,15 @@ int real_main(int argc, char** argv) {
setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
const char* ninja_command = argv[0];

int exit_code = ReadFlags(&argc, &argv, &options, &config);
config.parallelism = GuessParallelism();
int exit_code = -1;
exit_code = ReadFlagsFromEnv(&options, &config);
if (exit_code >= 0)
return exit_code;
exit_code = ReadFlags(&argc, &argv, &options, &config);
if (exit_code >= 0)
return exit_code;
PublishFlagsToEnv(options, config);

if (options.working_dir) {
// The formatting of this string, complete with funny quotes, is
Expand Down
28 changes: 28 additions & 0 deletions src/util.cc
Expand Up @@ -626,3 +626,31 @@ bool Truncate(const string& path, size_t size, string* err) {
}
return true;
}

void SplitArgv(char* flags, int* argc, char** argv, const int max_argc) {
assert(*argc < max_argc - 1);
char* start = flags;
{
char* s = flags;
while (true) {
while (*s == ' ')
++s;
if (*s == '\0')
break;
start = s;
while (*s != '\0' && *s != ' ')
++s;
if (*argc >= max_argc - 1)
Fatal("more than %d arguments in NINJA_FLAGS", max_argc);
argv[*argc] = start;
++*argc;
if (*s == '\0')
break;
else {
*s = '\0';
++s;
}
}
}
argv[*argc] = NULL;
}
6 changes: 6 additions & 0 deletions src/util.h
Expand Up @@ -106,4 +106,10 @@ string GetLastErrorString();
NORETURN void Win32Fatal(const char* function);
#endif

/// Split a string of flags into an array of flag strings.
/// @warning: Does not support shell quote
/// @warning: Modify @a flags in-place.
/// @warning: argc must be initialized to the index to start from.
void SplitArgv(char* flags, int* argc, char** argv, const int max_argc);

#endif // NINJA_UTIL_H_
113 changes: 113 additions & 0 deletions src/util_test.cc
Expand Up @@ -399,3 +399,116 @@ TEST(ElideMiddle, ElideInTheMiddle) {
string elided = ElideMiddle(input, 10);
EXPECT_EQ("012...789", elided);
}

TEST(SplitArgv, Empty) {
int argc = 0;
char* argv[16];
SplitArgv("", &argc, argv, 16);
EXPECT_EQ(0, argc);
EXPECT_EQ(NULL, argv[0]);
}

TEST(SplitArgv, OnlyWhitespace) {
int argc = 0;
char* argv[16];
SplitArgv(" ", &argc, argv, 16);
EXPECT_EQ(0, argc);
EXPECT_EQ(NULL, argv[0]);
}

TEST(SplitArgv, SingleFlags) {
int argc = 0;
char* argv[16];
char* flags = strdup("-n");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(1, argc);
EXPECT_TRUE(strcmp("-n", argv[0]) == 0);
EXPECT_EQ(NULL, argv[1]);
free(flags);
}

TEST(SplitArgv, SingleFlagsSurroundedBySpaces) {
int argc = 0;
char* argv[16];
char* flags = strdup(" -n ");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(1, argc);
EXPECT_TRUE(strcmp("-n", argv[0]) == 0);
EXPECT_EQ(NULL, argv[1]);
free(flags);
}

TEST(SplitArgv, SingleFlagsWithArgs) {
int argc = 0;
char* argv[16];
char* flags = strdup("-k 1000");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(2, argc);
EXPECT_TRUE(strcmp("-k", argv[0]) == 0);
EXPECT_TRUE(strcmp("1000", argv[1]) == 0);
EXPECT_EQ(NULL, argv[2]);
free(flags);
}

TEST(SplitArgv, SingleFlagsWithArgsStuck) {
int argc = 0;
char* argv[16];
char* flags = strdup("-k1000");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(1, argc);
EXPECT_TRUE(strcmp("-k1000", argv[0]) == 0);
EXPECT_EQ(NULL, argv[1]);
free(flags);
}

TEST(SplitArgv, TwoFlagsWithArgsStuck) {
int argc = 0;
char* argv[16];
char* flags = strdup("-j10 -k1000");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(2, argc);
EXPECT_TRUE(strcmp("-j10", argv[0]) == 0);
EXPECT_TRUE(strcmp("-k1000", argv[1]) == 0);
EXPECT_EQ(NULL, argv[2]);
free(flags);
}

TEST(SplitArgv, TwoFlagsWithArgsStuckSurroundedBySpaces) {
int argc = 0;
char* argv[16];
char* flags = strdup(" -j10 -k1000 ");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(2, argc);
EXPECT_TRUE(strcmp("-j10", argv[0]) == 0);
EXPECT_TRUE(strcmp("-k1000", argv[1]) == 0);
EXPECT_EQ(NULL, argv[2]);
free(flags);
}

TEST(SplitArgv, TwoFlagsWithArgs) {
int argc = 0;
char* argv[16];
char* flags = strdup("-j 10 -k 1000");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(4, argc);
EXPECT_TRUE(strcmp("-j", argv[0]) == 0);
EXPECT_TRUE(strcmp("10", argv[1]) == 0);
EXPECT_TRUE(strcmp("-k", argv[2]) == 0);
EXPECT_TRUE(strcmp("1000", argv[3]) == 0);
EXPECT_EQ(NULL, argv[4]);
free(flags);
}

TEST(SplitArgv, TwoFlagsWithArgsSurroundedBySpaces) {
int argc = 0;
char* argv[16];
char* flags = strdup(" -j 10 -k 1000 ");
SplitArgv(flags, &argc, argv, 16);
EXPECT_EQ(4, argc);
EXPECT_TRUE(strcmp("-j", argv[0]) == 0);
EXPECT_TRUE(strcmp("10", argv[1]) == 0);
EXPECT_TRUE(strcmp("-k", argv[2]) == 0);
EXPECT_TRUE(strcmp("1000", argv[3]) == 0);
EXPECT_EQ(NULL, argv[4]);
free(flags);
}

0 comments on commit 0634f90

Please sign in to comment.