http://git-wip-us.apache.org/repos/asf/lucy/blob/b7512609/common/charmonizer.c ---------------------------------------------------------------------- diff --git a/common/charmonizer.c b/common/charmonizer.c index 0e22822..47689c4 100644 --- a/common/charmonizer.c +++ b/common/charmonizer.c @@ -93,6 +93,16 @@ chaz_CC_set_warnings_as_errors(const int flag); void chaz_CC_add_extra_cflags(const char *); +/* Add include dir to extra cflags. + */ +void +chaz_CC_add_include_dir(const char *dir); + +/* Set optimization level. + */ +void +chaz_CC_set_optimization_level(const char *level); + /* Accessor for the compiler executable's string representation. */ const char* @@ -109,13 +119,25 @@ const char* chaz_CC_get_extra_cflags(void); int -chaz_CC_gcc_version_num(); +chaz_CC_gcc_version_num(void); const char* -chaz_CC_gcc_version(); +chaz_CC_gcc_version(void); int -chaz_CC_compiler_is_msvc(void); +chaz_CC_msvc_version_num(void); + +const char* +chaz_CC_link_command(void); + +const char* +chaz_CC_link_flags(void); + +const char* +chaz_CC_link_shared_obj_flag(void); + +const char* +chaz_CC_link_output_flag(void); #endif /* H_CHAZ_COMPILER */ @@ -325,6 +347,162 @@ chaz_HeadCheck_contains_member(const char *struct_name, const char *member, /***************************************************************************/ +#line 21 "src/Charmonizer/Core/Make.h" +/* Charmonizer/Core/Compiler.h + */ + +#ifndef H_CHAZ_MAKE +#define H_CHAZ_MAKE + +typedef struct chaz_MakeFile chaz_MakeFile; +typedef struct chaz_MakeVar chaz_MakeVar; +typedef struct chaz_MakeRule chaz_MakeRule; + +typedef void (*chaz_Make_list_files_callback_t)(char *file, void *context); + +/** Initialize the environment. + */ +void +chaz_Make_init(void); + +/** Clean up the environment. + */ +void +chaz_Make_clean_up(void); + +/** Return the name of the detected 'make' executable. + */ +const char* +chaz_Make_get_make(void); + +/** Recursively list files in a directory. For every file a callback is called + * with the filename and a context variable. + * + * @param dir Directory to search in. + * @param ext File extension to search for. + * @param callback Callback to call for every matching file. + * @param context Context variable to pass to callback. + */ +void +chaz_Make_list_files(const char *dir, const char *ext, + chaz_Make_list_files_callback_t callback, void *context); + +/** MakeFile constructor. + */ +chaz_MakeFile* +chaz_MakeFile_new(); + +/** Add a variable to a makefile. + * + * @param makefile The makefile. + * @param name Name of the variable. + * @param value Value of the variable. Can be NULL if you want add content + * later. + * @return a MakeVar. + */ +chaz_MakeVar* +chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name, + const char *value); + +/** Add a rule to a makefile. + * + * @param makefile The makefile. + * @param target The first target of the rule. Can be NULL if you want to add + * targets later. + * @param prereq The first prerequisite of the rule. Can be NULL if you want to + * add prerequisites later. + * @return a MakeRule. + */ +chaz_MakeRule* +chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target, + const char *prereq); + +/** Add a file to the 'clean' target. + * + * @param makefile The makefile. + * @param target The filename. + */ +void +chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target); + +/** Add a rule to link an executable. The executable will also be added to the + * list of files to clean. + * + * @param makefile The makefile. + * @param exe The name of the executable. + * @param objects The list of object files. + */ +void +chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe, + const char *objects); + +/** Add a rule to link a shared object. The shared object will also be added to + * the list of files to clean. + * + * @param makefile The makefile. + * @param shared_obj The name of the shared object. + * @param objects The list of object files. + */ +void +chaz_MakeFile_add_shared_obj(chaz_MakeFile *makefile, const char *shared_obj, + const char *objects); + +/** Write the makefile to a file named 'Makefile' in the current directory. + * + * @param makefile The makefile. + */ +void +chaz_MakeFile_write(chaz_MakeFile *makefile); + +/** Append content to a makefile variable. The new content will be separated + * from the existing content with whitespace. + * + * @param var The variable. + * @param element The additional content. + */ +void +chaz_MakeVar_append(chaz_MakeVar *var, const char *element); + +/** Add another target to a makefile rule. + * + * @param rule The rule. + * @param target The additional rule. + */ +void +chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target); + +/** Add another prerequisite to a makefile rule. + * + * @param rule The rule. + * @param prereq The additional prerequisite. + */ +void +chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq); + +/** Add a command to a rule. + * + * @param rule The rule. + * @param command The additional command. + */ +void +chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command); + +/** Add one or more commands to call another makefile recursively. + * + * @param rule The rule. + * @param dir The directory in which to call the makefile. + * @param target The target to call. Pass NULL for the default target. + */ +void +chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir, + const char *target); + +#endif /* H_CHAZ_MAKE */ + + + +/***************************************************************************/ + #line 21 "src/Charmonizer/Core/OperatingSystem.h" /* Charmonizer/Core/OperatingSystem.h - abstract an operating system down to a few * variables. @@ -333,6 +511,9 @@ chaz_HeadCheck_contains_member(const char *struct_name, const char *member, #ifndef H_CHAZ_OPER_SYS #define H_CHAZ_OPER_SYS +#define CHAZ_OS_POSIX 1 +#define CHAZ_OS_CMD_EXE 2 + /* Safely remove a file named [name]. Needed because of Windows quirks. * Returns true on success, false on failure. */ @@ -358,6 +539,11 @@ chaz_OS_run_redirected(const char *command, const char *path); int chaz_OS_run_local_redirected(const char *command, const char *path); +/* Run a command and return the output from stdout. + */ +char* +chaz_OS_run_and_capture(const char *command, size_t *output_len); + /* Attempt to create a directory. */ void @@ -368,6 +554,17 @@ chaz_OS_mkdir(const char *filepath); void chaz_OS_rmdir(const char *filepath); +/* Return the operating system name. + */ +const char* +chaz_OS_name(void); + +int +chaz_OS_is_darwin(void); + +int +chaz_OS_is_cygwin(void); + /* Return the extension for an executable on this system. */ const char* @@ -378,11 +575,21 @@ chaz_OS_exe_ext(void); const char* chaz_OS_obj_ext(void); +/* Return the extension for a shared object on this system. + */ +const char* +chaz_OS_shared_obj_ext(void); + /* Return the equivalent of /dev/null on this system. */ const char* chaz_OS_dev_null(void); +/* Return the shell type of this system. + */ +int +chaz_OS_shell_type(void); + /* Initialize the Charmonizer/Core/OperatingSystem module. */ void @@ -526,10 +733,10 @@ chaz_Probe_gcc_version_num(void); const char* chaz_Probe_gcc_version(void); -/* Returns true if the compiler is MSVC. +/* Return the integer version of MSVC defined by _MSC_VER */ int -chaz_Probe_compiler_is_msvc(void); +chaz_Probe_msvc_version_num(void); #endif /* Include guard. */ @@ -1422,6 +1629,34 @@ chaz_CC_add_extra_cflags(const char *flags) { } } +void +chaz_CC_add_include_dir(const char *dir) { + size_t size = strlen(chaz_CC.include_flag) + strlen(dir) + 1; + char *flag = (char*)malloc(size); + sprintf(flag, "%s%s", chaz_CC.include_flag, dir); + chaz_CC_add_extra_cflags(flag); + free(flag); +} + +void +chaz_CC_set_optimization_level(const char *level) { + const char *opt_flag; + char *flag; + size_t size; + + if (chaz_CC.intval__MSC_VER) { + opt_flag = "/O"; + } + else { + opt_flag = "-O"; + } + size = strlen(opt_flag) + strlen(level) + 1; + flag = (char*)malloc(size); + sprintf(flag, "%s%s", opt_flag, level); + chaz_CC_add_extra_cflags(flag); + free(flag); +} + const char* chaz_CC_get_cc(void) { return chaz_CC.cc_command; @@ -1450,10 +1685,49 @@ chaz_CC_gcc_version(void) { } int -chaz_CC_compiler_is_msvc(void) { - return !!chaz_CC.intval__MSC_VER; +chaz_CC_msvc_version_num(void) { + return chaz_CC.intval__MSC_VER; +} + +const char* +chaz_CC_link_command() { + if (chaz_CC.intval__MSC_VER) { + return "link"; + } + else { + return chaz_CC.cc_command; + } } +const char* +chaz_CC_link_flags() { + return ""; +} + +const char* +chaz_CC_link_shared_obj_flag() { + if (chaz_CC.intval__MSC_VER) { + return "/DLL"; + } + else if (chaz_OS_is_darwin()) { + return "-dynamiclib "; + } + else { + return "-shared"; + } +} + +const char* +chaz_CC_link_output_flag() { + if (chaz_CC.intval__MSC_VER) { + return "/OUT:"; + } + else { + return "-o "; + } +} + + /***************************************************************************/ @@ -2559,25 +2833,587 @@ chaz_HeadCheck_maybe_add_to_cache(const char *header_name, int exists) { /***************************************************************************/ +#line 17 "src/Charmonizer/Core/Make.c" +#include <ctype.h> +#include <string.h> +/* #include "Charmonizer/Core/Make.h" */ +/* #include "Charmonizer/Core/Compiler.h" */ +/* #include "Charmonizer/Core/OperatingSystem.h" */ +/* #include "Charmonizer/Core/Util.h" */ + +struct chaz_MakeVar { + char *name; + char *value; + size_t num_elements; +}; + +struct chaz_MakeRule { + char *targets; + char *prereqs; + char *commands; +}; + +struct chaz_MakeFile { + chaz_MakeVar **vars; + size_t num_vars; + chaz_MakeRule **rules; + size_t num_rules; + char **cleanups; + size_t num_cleanups; +}; + +/* Static vars. */ +static struct { + char *make_command; + int is_gnu_make; + int is_nmake; +} chaz_Make = { + NULL, + 0, 0 +}; + +/* Detect make command. + * + * The argument list must be a NULL-terminated series of different spellings + * of `make`, which will be auditioned in the order they are supplied. Here + * are several possibilities: + * + * make + * gmake + * nmake + * dmake + */ +static int +chaz_Make_detect(const char *make1, ...); + +static int +chaz_Make_audition(const char *make); + +void +chaz_Make_init(void) { + const char *make; + + chaz_Make_detect("make", "gmake", "nmake", "dmake", NULL); + make = chaz_Make.make_command; + + if (make) { + if (strcmp(make, "make") == 0 || strcmp(make, "gmake") == 0) { + /* TODO: Add a feature test for GNU make. */ + chaz_Make.is_gnu_make = 1; + } + else if (strcmp(make, "nmake") == 0) { + chaz_Make.is_nmake = 1; + } + } +} + +void +chaz_Make_clean_up(void) { + free(chaz_Make.make_command); +} + +const char* +chaz_Make_get_make(void) { + return chaz_Make.make_command; +} + +static int +chaz_Make_detect(const char *make1, ...) { + va_list args; + const char *candidate; + int found = 0; + const char makefile_content[] = "foo:\n\techo \"foo!\"\n"; + chaz_Util_write_file("_charm_Makefile", makefile_content); + + /* Audition candidates. */ + found = chaz_Make_audition(make1); + va_start(args, make1); + while (!found && (NULL != (candidate = va_arg(args, const char*)))) { + found = chaz_Make_audition(candidate); + } + va_end(args); + + chaz_Util_remove_and_verify("_charm_Makefile"); + + return found; +} + +static int +chaz_Make_audition(const char *make) { + int succeeded = 0; + const char pattern[] = "%s -f _charm_Makefile"; + size_t size = strlen(make) + sizeof(pattern) + 10; + char *command = (char*)malloc(size); + sprintf(command, pattern, make); + + chaz_Util_remove_and_verify("_charm_foo"); + chaz_OS_run_redirected(command, "_charm_foo"); + if (chaz_Util_can_open_file("_charm_foo")) { + size_t len; + char *content = chaz_Util_slurp_file("_charm_foo", &len); + if (NULL != strstr(content, "foo!")) { + succeeded = 1; + } + free(content); + } + chaz_Util_remove_and_verify("_charm_foo"); + + if (succeeded) { + chaz_Make.make_command = chaz_Util_strdup(make); + } + + free(command); + return succeeded; +} + +chaz_MakeFile* +chaz_MakeFile_new() { + chaz_MakeFile *makefile = (chaz_MakeFile*)malloc(sizeof(chaz_MakeFile)); + + makefile->vars = (chaz_MakeVar**)malloc(sizeof(chaz_MakeVar*)); + makefile->vars[0] = NULL; + makefile->num_vars = 0; + + makefile->rules = (chaz_MakeRule**)malloc(sizeof(chaz_MakeRule*)); + makefile->rules[0] = NULL; + makefile->num_rules = 0; + + makefile->cleanups = (char**)malloc(sizeof(char*)); + makefile->cleanups[0] = NULL; + makefile->num_cleanups = 0; + + return makefile; +} + +chaz_MakeVar* +chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name, + const char *value) { + chaz_MakeVar *var = (chaz_MakeVar*)malloc(sizeof(chaz_MakeVar)); + chaz_MakeVar **vars = makefile->vars; + size_t num_vars = makefile->num_vars + 1; + + var->name = chaz_Util_strdup(name); + var->value = chaz_Util_strdup(""); + var->num_elements = 0; + + if (value) { chaz_MakeVar_append(var, value); } + + vars = (chaz_MakeVar**)realloc(vars, + (num_vars + 1) * sizeof(chaz_MakeVar*)); + vars[num_vars-1] = var; + vars[num_vars] = NULL; + makefile->vars = vars; + makefile->num_vars = num_vars; + + return var; +} + +chaz_MakeRule* +chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target, + const char *prereq) { + chaz_MakeRule *rule = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule)); + chaz_MakeRule **rules = makefile->rules; + size_t num_rules = makefile->num_rules + 1; + + rule->targets = NULL; + rule->prereqs = NULL; + rule->commands = NULL; + + if (target) { chaz_MakeRule_add_target(rule, target); } + if (prereq) { chaz_MakeRule_add_prereq(rule, prereq); } + + rules = (chaz_MakeRule**)realloc(rules, + (num_rules + 1) * sizeof(chaz_MakeRule*)); + rules[num_rules-1] = rule; + rules[num_rules] = NULL; + makefile->rules = rules; + makefile->num_rules = num_rules; + + return rule; +} + +void +chaz_MakeFile_add_to_cleanup(chaz_MakeFile *makefile, const char *target) { + char *cleanup = chaz_Util_strdup(target); + char **cleanups = makefile->cleanups; + size_t num_cleanups = makefile->num_cleanups + 1; + + cleanups = (char**)realloc(cleanups, (num_cleanups + 1) * sizeof(char*)); + cleanups[num_cleanups-1] = cleanup; + cleanups[num_cleanups] = NULL; + makefile->cleanups = cleanups; + makefile->num_cleanups = num_cleanups; +} + +void +chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe, + const char *objects) { + const char *pattern = "%s %s %s %s%s"; + const char *link = chaz_CC_link_command(); + const char *link_flags = chaz_CC_link_flags(); + const char *output_flag = chaz_CC_link_output_flag(); + chaz_MakeRule *rule; + char *command; + size_t size; + + rule = chaz_MakeFile_add_rule(makefile, exe, objects); + + size = strlen(pattern) + + strlen(link) + + strlen(link_flags) + + strlen(objects) + + strlen(output_flag) + + strlen(exe) + + 50; + command = (char*)malloc(size); + sprintf(command, pattern, link, link_flags, objects, output_flag, exe); + chaz_MakeRule_add_command(rule, command); + + chaz_MakeFile_add_to_cleanup(makefile, exe); +} + +void +chaz_MakeFile_add_shared_obj(chaz_MakeFile *makefile, const char *shared_obj, + const char *objects) { + const char *pattern = "%s %s %s %s %s%s"; + const char *link = chaz_CC_link_command(); + const char *shobj_flags = chaz_CC_link_shared_obj_flag(); + const char *link_flags = chaz_CC_link_flags(); + const char *output_flag = chaz_CC_link_output_flag(); + chaz_MakeRule *rule; + char *command; + size_t size; + + rule = chaz_MakeFile_add_rule(makefile, shared_obj, objects); + + size = strlen(pattern) + + strlen(link) + + strlen(shobj_flags) + + strlen(link_flags) + + strlen(objects) + + strlen(output_flag) + + strlen(shared_obj) + + 50; + command = (char*)malloc(size); + sprintf(command, pattern, link, shobj_flags, link_flags, objects, + output_flag, shared_obj); + chaz_MakeRule_add_command(rule, command); + + chaz_MakeFile_add_to_cleanup(makefile, shared_obj); +} + +void +chaz_MakeFile_write(chaz_MakeFile *makefile) { + int shell_type = chaz_OS_shell_type(); + FILE *file; + size_t i; + + file = fopen("Makefile", "w"); + if (!file) { + chaz_Util_die("Can't open Makefile\n"); + } + + for (i = 0; makefile->vars[i]; i++) { + chaz_MakeVar *var = makefile->vars[i]; + fprintf(file, "%s = %s\n", var->name, var->value); + } + fprintf(file, "\n"); + + for (i = 0; makefile->rules[i]; i++) { + chaz_MakeRule *rule = makefile->rules[i]; + fprintf(file, "%s :", rule->targets); + if (rule->prereqs) { + fprintf(file, " %s", rule->prereqs); + } + fprintf(file, "\n"); + if (rule->commands) { + fprintf(file, "%s", rule->commands); + } + fprintf(file, "\n"); + } + + if (makefile->cleanups[0]) { + if (shell_type == CHAZ_OS_POSIX) { + fprintf(file, "clean :\n\trm -f"); + for (i = 0; makefile->cleanups[i]; i++) { + const char *cleanup = makefile->cleanups[i]; + fprintf(file, " \\\n\t %s", cleanup); + } + fprintf(file, "\n\n"); + } + else if (shell_type == CHAZ_OS_CMD_EXE) { + fprintf(file, "clean :\n"); + for (i = 0; makefile->cleanups[i]; i++) { + const char *cleanup = makefile->cleanups[i]; + fprintf(file, "\tfor %%i in (%s) do @if exist %%i del /f %%i\n", + cleanup); + } + fprintf(file, "\n"); + } + else { + chaz_Util_die("Unsupported shell type: %d", shell_type); + } + } + + fprintf(file, "distclean : clean\n"); + if (shell_type == CHAZ_OS_POSIX) { + fprintf(file, "\trm -f charmonizer$(EXE_EXT) charmony.h Makefile\n\n"); + } + else if (shell_type == CHAZ_OS_CMD_EXE) { + fprintf(file, + "\tfor %%i in (charmonizer$(EXE_EXT) charmonizer$(OBJ_EXT)" + " charmony.h Makefile) do @if exist %%i del /f %%i\n\n"); + } + else { + chaz_Util_die("Unsupported shell type: %d", shell_type); + } + + if (chaz_Make.is_nmake) { + /* Inference rule for .c files. */ + fprintf(file, ".c.obj :\n"); + if (chaz_CC_msvc_version_num()) { + fprintf(file, "\t$(CC) $(CFLAGS) /c $< /Fo$@\n\n"); + } + else { + fprintf(file, "\t$(CC) $(CFLAGS) -c $< -o $@\n\n"); + } + } + + fclose(file); +} + +void +chaz_MakeVar_append(chaz_MakeVar *var, const char *element) { + char *value; + + if (element[0] == '\0') { return; } + + if (var->num_elements == 0) { + value = chaz_Util_strdup(element); + } + else { + value = (char*)malloc(strlen(var->value) + strlen(element) + 20); + + if (var->num_elements == 1) { + sprintf(value, "\\\n %s \\\n %s", var->value, element); + } + else { + sprintf(value, "%s \\\n %s", var->value, element); + } + } + + free(var->value); + var->value = value; + var->num_elements++; +} + +void +chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) { + char *targets; + + if (!rule->targets) { + targets = chaz_Util_strdup(target); + } + else { + targets = (char*)malloc(strlen(rule->targets) + strlen(target) + 20); + sprintf(targets, "%s %s", rule->targets, target); + free(rule->targets); + } + + rule->targets = targets; +} + +void +chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq) { + char *prereqs; + + if (!rule->prereqs) { + prereqs = chaz_Util_strdup(prereq); + } + else { + prereqs = (char*)malloc(strlen(rule->prereqs) + strlen(prereq) + 20); + sprintf(prereqs, "%s %s", rule->prereqs, prereq); + free(rule->prereqs); + } + + rule->prereqs = prereqs; +} + +void +chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) { + char *commands; + + if (!rule->commands) { + commands = (char*)malloc(strlen(command) + 20); + sprintf(commands, "\t%s\n", command); + } + else { + commands = (char*)malloc(strlen(rule->commands) + strlen(command) + 20); + sprintf(commands, "%s\t%s\n", rule->commands, command); + free(rule->commands); + } + + rule->commands = commands; +} + +void +chaz_MakeRule_add_command_make(chaz_MakeRule *rule, const char *dir, + const char *target) { + const char *make = chaz_Make.make_command; + char *command; + + if (chaz_Make.is_gnu_make) { + if (!target) { + size_t size = strlen(dir) + 20; + command = (char*)malloc(size); + sprintf(command, "$(MAKE) -C %s", dir); + } + else { + size_t size = strlen(dir) + strlen(target) + 20; + command = (char*)malloc(size); + sprintf(command, "$(MAKE) -C %s %s", dir, target); + } + chaz_MakeRule_add_command(rule, command); + free(command); + } + else if (chaz_Make.is_nmake) { + command = (char*)malloc(strlen(dir) + 20); + sprintf(command, "cd %s", dir); + chaz_MakeRule_add_command(rule, command); + free(command); + + if (!target) { + chaz_MakeRule_add_command(rule, "$(MAKE)"); + } + else { + size_t size = strlen(target) + 20; + command = (char*)malloc(size); + sprintf(command, "$(MAKE) %s", target); + chaz_MakeRule_add_command(rule, command); + free(command); + } + + chaz_MakeRule_add_command(rule, "cd $(MAKEDIR)"); + } + else { + chaz_Util_die("Couldn't find a supported 'make' utility."); + } +} + +void +chaz_Make_list_files(const char *dir, const char *ext, + chaz_Make_list_files_callback_t callback, void *context) { + int shell_type = chaz_OS_shell_type(); + const char *pattern; + char *command; + char *list; + char *prefix; + char *file; + size_t command_size; + size_t list_len; + size_t prefix_len; + + /* List files using shell. */ + + if (shell_type == CHAZ_OS_POSIX) { + pattern = "find %s -name '*.%s' -type f"; + } + else if (shell_type == CHAZ_OS_CMD_EXE) { + pattern = "dir %s\\*.%s /s /b /a-d"; + } + else { + chaz_Util_die("Unknown shell type %d", shell_type); + } + + command_size = strlen(pattern) + strlen(dir) + strlen(ext) + 10; + command = (char*)malloc(command_size); + sprintf(command, pattern, dir, ext); + list = chaz_OS_run_and_capture(command, &list_len); + free(command); + if (!list) { + chaz_Util_die("Failed to list files in '%s'", dir); + } + list[list_len-1] = 0; + + /* Find directory prefix to strip from files */ + + if (shell_type == CHAZ_OS_POSIX) { + prefix_len = strlen(dir); + prefix = (char*)malloc(prefix_len + 2); + memcpy(prefix, dir, prefix_len); + prefix[prefix_len++] = '/'; + prefix[prefix_len] = '\0'; + } + else { + char *output; + size_t output_len; + + /* 'dir /s' returns absolute paths, so we have to find the absolute + * path of the directory. This is done by using the variable + * substitution feature of the 'for' command. + */ + pattern = "for %%I in (%s) do @echo %%~fI"; + command_size = strlen(pattern) + strlen(dir) + 10; + command = (char*)malloc(command_size); + sprintf(command, pattern, dir); + output = chaz_OS_run_and_capture(command, &output_len); + free(command); + if (!output) { chaz_Util_die("Failed to find absolute path"); } + + /* Strip whitespace from end of output. */ + for (prefix_len = output_len; prefix_len > 0; --prefix_len) { + if (!isspace(output[prefix_len-1])) { break; } + } + prefix = (char*)malloc(prefix_len + 2); + memcpy(prefix, output, prefix_len); + prefix[prefix_len++] = '\\'; + prefix[prefix_len] = '\0'; + free(output); + } + + /* Iterate file list and invoke callback. */ + + for (file = strtok(list, "\r\n"); file; file = strtok(NULL, "\r\n")) { + if (strlen(file) <= prefix_len + || memcmp(file, prefix, prefix_len) != 0 + ) { + chaz_Util_die("Expected prefix '%s' for file name '%s'", prefix, + file); + } + + callback(file + prefix_len, context); + } + + free(prefix); + free(list); +} + + +/***************************************************************************/ + #line 17 "src/Charmonizer/Core/OperatingSystem.c" #include <stdlib.h> #include <string.h> #include <stdarg.h> +#include <ctype.h> /* #include "Charmonizer/Core/Compiler.h" */ /* #include "Charmonizer/Core/Util.h" */ /* #include "Charmonizer/Core/ConfWriter.h" */ /* #include "Charmonizer/Core/OperatingSystem.h" */ +#define CHAZ_OS_TARGET_PATH "_charmonizer_target" +#define CHAZ_OS_NAME_MAX 31 + static struct { + char name[CHAZ_OS_NAME_MAX+1]; char dev_null[20]; char exe_ext[5]; char obj_ext[5]; + char shared_obj_ext[7]; char local_command_start[3]; int shell_type; -} chaz_OS = { "", "", "", "", 0 }; -#define CHAZ_OS_POSIX 1 -#define CHAZ_OS_CMD_EXE 2 +} chaz_OS = { "", "", "", "", "", "", 0 }; void chaz_OS_init(void) { @@ -2591,16 +3427,43 @@ chaz_OS_init(void) { /* Detect shell based on whether the bitbucket is "/dev/null" or "nul". */ if (chaz_Util_can_open_file("/dev/null")) { + char *uname; + size_t uname_len; + size_t i; + + chaz_OS.shell_type = CHAZ_OS_POSIX; + + /* Detect Unix name. */ + uname = chaz_OS_run_and_capture("uname", &uname_len); + for (i = 0; i < CHAZ_OS_NAME_MAX && i < uname_len; i++) { + char c = uname[i]; + if (!c || isspace(c)) { break; } + chaz_OS.name[i] = tolower(c); + } + if (i > 0) { chaz_OS.name[i] = '\0'; } + else { strcpy(chaz_OS.name, "unknown_unix"); } + free(uname); + strcpy(chaz_OS.dev_null, "/dev/null"); strcpy(chaz_OS.exe_ext, ""); strcpy(chaz_OS.obj_ext, ".o"); + if (memcmp(chaz_OS.name, "darwin", 6) == 0) { + strcpy(chaz_OS.shared_obj_ext, ".dylib"); + } + else if (memcmp(chaz_OS.name, "cygwin", 6) == 0) { + strcpy(chaz_OS.shared_obj_ext, ".dll"); + } + else { + strcpy(chaz_OS.shared_obj_ext, ".so"); + } strcpy(chaz_OS.local_command_start, "./"); - chaz_OS.shell_type = CHAZ_OS_POSIX; } else if (chaz_Util_can_open_file("nul")) { + strcpy(chaz_OS.name, "windows"); strcpy(chaz_OS.dev_null, "nul"); strcpy(chaz_OS.exe_ext, ".exe"); strcpy(chaz_OS.obj_ext, ".obj"); + strcpy(chaz_OS.shared_obj_ext, ".dll"); strcpy(chaz_OS.local_command_start, ".\\"); chaz_OS.shell_type = CHAZ_OS_CMD_EXE; } @@ -2611,6 +3474,21 @@ chaz_OS_init(void) { } const char* +chaz_OS_name(void) { + return chaz_OS.name; +} + +int +chaz_OS_is_darwin(void) { + return memcmp(chaz_OS.name, "darwin", 6) == 0; +} + +int +chaz_OS_is_cygwin(void) { + return memcmp(chaz_OS.name, "cygwin", 6) == 0; +} + +const char* chaz_OS_exe_ext(void) { return chaz_OS.exe_ext; } @@ -2621,11 +3499,21 @@ chaz_OS_obj_ext(void) { } const char* +chaz_OS_shared_obj_ext(void) { + return chaz_OS.shared_obj_ext; +} + +const char* chaz_OS_dev_null(void) { return chaz_OS.dev_null; } int +chaz_OS_shell_type(void) { + return chaz_OS.shell_type; +} + +int chaz_OS_remove(const char *name) { /* * On Windows it can happen that another process, typically a @@ -2699,6 +3587,15 @@ chaz_OS_run_redirected(const char *command, const char *path) { return retval; } +char* +chaz_OS_run_and_capture(const char *command, size_t *output_len) { + char *output; + chaz_OS_run_redirected(command, CHAZ_OS_TARGET_PATH); + output = chaz_Util_slurp_file(CHAZ_OS_TARGET_PATH, output_len); + chaz_Util_remove_and_verify(CHAZ_OS_TARGET_PATH); + return output; +} + void chaz_OS_mkdir(const char *filepath) { char *command = NULL; @@ -3001,6 +3898,7 @@ chaz_Probe_init(struct chaz_CLIArgs *args) { chaz_CC_init(args->cc, args->cflags); chaz_ConfWriter_init(); chaz_HeadCheck_init(); + chaz_Make_init(); /* Enable output. */ if (args->charmony_h) { @@ -3030,6 +3928,7 @@ chaz_Probe_clean_up(void) { /* Dispatch various clean up routines. */ chaz_ConfWriter_clean_up(); chaz_CC_clean_up(); + chaz_Make_clean_up(); if (chaz_Util_verbosity) { printf("Cleanup complete.\n"); } } @@ -3045,8 +3944,8 @@ chaz_Probe_gcc_version(void) { } int -chaz_Probe_compiler_is_msvc(void) { - return chaz_CC_compiler_is_msvc(); +chaz_Probe_msvc_version_num(void) { + return chaz_CC_msvc_version_num(); } /***************************************************************************/ @@ -4888,27 +5787,33 @@ S_add_compiler_flags(struct chaz_CLIArgs *args) { /* Only core source files require this -- not our headers and * autogenerated files. */ chaz_CC_add_extra_cflags("-std=gnu99 -D_GNU_SOURCE"); + + /* When compiling for Perl bindings, define HAS_BOOL so that the Perl + * headers don't redefine 'bool' in conflict with C++. + * + * TODO: Compile all files that #include Perl headers separately and + * remove this directive. + */ + if (args->charmony_pm) { + chaz_CC_add_extra_cflags("-DHAS_BOOL"); + } } - else if (chaz_Probe_compiler_is_msvc()) { + else if (chaz_Probe_msvc_version_num()) { /* Compile as C++ under MSVC. */ chaz_CC_add_extra_cflags("/TP"); /* Thwart stupid warnings. */ - chaz_CC_add_extra_cflags("-D_CRT_SECURE_NO_WARNINGS"); - chaz_CC_add_extra_cflags("-D_SCL_SECURE_NO_WARNINGS"); + chaz_CC_add_extra_cflags("/D_CRT_SECURE_NO_WARNINGS"); + chaz_CC_add_extra_cflags("/D_SCL_SECURE_NO_WARNINGS"); - /* Redefine 'for' to fix broken 'for' scoping under MSVC6. */ - chaz_CC_add_extra_cflags("-Dfor=\"if(0);else for\""); - } + if (chaz_Probe_msvc_version_num() < 1300) { + /* Redefine 'for' to fix broken 'for' scoping under MSVC6. */ + chaz_CC_add_extra_cflags("/Dfor=\"if(0);else for\""); + } - /* When compiling for Perl bindings, define HAS_BOOL so that the Perl - * headers don't redefine 'bool' in conflict with C++. - * - * TODO: Compile all files that #include Perl headers separately and - * remove this directive. - */ - if (args->charmony_pm) { - chaz_CC_add_extra_cflags("-DHAS_BOOL"); + if (args->charmony_pm) { + chaz_CC_add_extra_cflags("/DHAS_BOOL"); + } } }
