#define STB_DEFINE #include "stb.h" // true if no error int run_command(char *batch_file, char *command) { char buffer[4096]; if (batch_file[0]) { sprintf(buffer, "%s && %s", batch_file, command); return system(buffer) == 0; } else { return system(command) == 0; } } typedef struct { char *compiler_name; char *batchfile; char *objdir; char *compiler; char *args; char *link; } compiler_info; compiler_info *compilers; char *shared_args; char *shared_link; typedef struct { char *filelist; } project_info; project_info *projects; enum { NONE, IN_COMPILERS, IN_ARGS, IN_PROJECTS, IN_LINK }; int main(int argc, char **argv) { int state = NONE; int i,j,n; char **line; if (argc != 2) stb_fatal("Usage: stb_build_matrix {build-file}\n"); line = stb_stringfile(argv[1], &n); if (line == 0) stb_fatal("Couldn't open file '%s'\n", argv[1]); for (i=0; i < n; ++i) { char *p = stb_trimwhite(line[i]); if (p[0] == 0) continue; else if (p[0] == '#') continue; else if (0 == stricmp(p, "[compilers]")) { state = IN_COMPILERS; } else if (0 == stricmp(p, "[args]" )) { state = IN_ARGS ; shared_args = NULL; } else if (0 == stricmp(p, "[projects]" )) { state = IN_PROJECTS ; } else if (0 == stricmp(p, "[link]" )) { state = IN_LINK ; shared_link = NULL; } else { switch (state) { case NONE: stb_fatal("Invalid text outside section at line %d.", i+1); case IN_COMPILERS: { char buffer[4096]; int count; compiler_info ci; char **tokens = stb_tokens_stripwhite(p, ",", &count), *batch; if (count > 3) stb_fatal("Expecting name and batch file name at line %d.", i+1); batch = (count==1 ? tokens[0] : tokens[1]); if (strlen(batch)) sprintf(buffer, "c:\\%s.bat", batch); else strcpy(buffer, ""); ci.compiler_name = strdup(tokens[0]); ci.batchfile = strdup(buffer); ci.compiler = count==3 ? strdup(tokens[2]) : "cl"; if (0==strnicmp(batch, "vcvars_", 7)) ci.objdir = strdup(stb_sprintf("%s_%d", batch+7, i)); else ci.objdir = strdup(stb_sprintf("%s_%d", batch, i)); ci.args = shared_args; ci.link = shared_link; stb_arr_push(compilers, ci); break; } case IN_ARGS: { stb_arr_push(shared_args, ' '); for (j=0; p[j] != 0; ++j) stb_arr_push(shared_args, p[j]); break; } case IN_LINK: { stb_arr_push(shared_link, ' '); for (j=0; p[j] != 0; ++j) stb_arr_push(shared_link, p[j]); break; } case IN_PROJECTS: { project_info pi; pi.filelist = strdup(p); stb_arr_push(projects, pi); break; } } } } _mkdir("obj"); for (j=0; j < stb_arr_len(compilers); ++j) { char command[4096]; for (i=0; i < stb_arr_len(projects); ++i) { int r; _mkdir(stb_sprintf("obj/%s", compilers[j].objdir)); if (stb_suffix(compilers[j].compiler, "cl")) sprintf(command, "%s %.*s %s /link %.*s", compilers[j].compiler, stb_arr_len(compilers[j].args), compilers[j].args, projects[i].filelist, stb_arr_len(compilers[j].link), compilers[j].link); else sprintf(command, "%s %.*s %s %.*s", compilers[j].compiler, stb_arr_len(compilers[j].args), compilers[j].args, projects[i].filelist, stb_arr_len(compilers[j].link), compilers[j].link); r = run_command(compilers[j].batchfile, command); stbprint("{%c== Compiler %s == Building %s}\n", r ? '$' : '!', compilers[j].compiler_name, projects[i].filelist); system("if EXIST *.obj del /q *.obj"); system("if EXIST *.o del /q *.o"); if (!r) return 1; } } return 0; }