http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8610c2e4/compiler/common/charmonizer.c ---------------------------------------------------------------------- diff --git a/compiler/common/charmonizer.c b/compiler/common/charmonizer.c index 46d0610..19eff00 100644 --- a/compiler/common/charmonizer.c +++ b/compiler/common/charmonizer.c @@ -36,61 +36,6 @@ /***************************************************************************/ -#line 21 "src/Charmonizer/Core/Library.h" -/* Charmonizer/Core/Library.h - */ - -#ifndef H_CHAZ_LIB -#define H_CHAZ_LIB - -typedef struct chaz_Lib chaz_Lib; - -chaz_Lib* -chaz_Lib_new_shared(const char *name, const char *version, - const char *major_version); - -chaz_Lib* -chaz_Lib_new_static(const char *name); - -void -chaz_Lib_destroy(chaz_Lib *flags); - -const char* -chaz_Lib_get_name(chaz_Lib *lib); - -const char* -chaz_Lib_get_version(chaz_Lib *lib); - -const char* -chaz_Lib_get_major_version(chaz_Lib *lib); - -int -chaz_Lib_is_shared(chaz_Lib *lib); - -int -chaz_Lib_is_static(chaz_Lib *lib); - -char* -chaz_Lib_filename(chaz_Lib *lib); - -char* -chaz_Lib_major_version_filename(chaz_Lib *lib); - -char* -chaz_Lib_no_version_filename(chaz_Lib *lib); - -char* -chaz_Lib_implib_filename(chaz_Lib *lib); - -char* -chaz_Lib_export_filename(chaz_Lib *lib); - -#endif /* H_CHAZ_LIB */ - - - -/***************************************************************************/ - #line 21 "src/Charmonizer/Core/CFlags.h" /* Charmonizer/Core/CFlags.h */ @@ -98,8 +43,6 @@ chaz_Lib_export_filename(chaz_Lib *lib); #ifndef H_CHAZ_CFLAGS #define H_CHAZ_CFLAGS -/* #include "Charmonizer/Core/Library.h" */ - #define CHAZ_CFLAGS_STYLE_POSIX 1 #define CHAZ_CFLAGS_STYLE_GNU 2 #define CHAZ_CFLAGS_STYLE_MSVC 3 @@ -151,10 +94,9 @@ void chaz_CFlags_hide_symbols(chaz_CFlags *flags); void -chaz_CFlags_link_shared_library(chaz_CFlags *flags); - -void -chaz_CFlags_set_shared_library_version(chaz_CFlags *flags, chaz_Lib *lib); +chaz_CFlags_link_shared_library(chaz_CFlags *flags, const char *basename, + const char *version, + const char *major_version); void chaz_CFlags_set_link_output(chaz_CFlags *flags, const char *filename); @@ -163,10 +105,11 @@ void chaz_CFlags_add_library_path(chaz_CFlags *flags, const char *directory); void -chaz_CFlags_add_library(chaz_CFlags *flags, chaz_Lib *lib); +chaz_CFlags_add_shared_lib(chaz_CFlags *flags, const char *dir, + const char *basename, const char *major_version); void -chaz_CFlags_add_external_library(chaz_CFlags *flags, const char *library); +chaz_CFlags_add_external_lib(chaz_CFlags *flags, const char *library); void chaz_CFlags_enable_code_coverage(chaz_CFlags *flags); @@ -402,6 +345,9 @@ chaz_CC_sun_c_version_num(void); int chaz_CC_is_cygwin(void); +int +chaz_CC_is_mingw(void); + const char* chaz_CC_link_command(void); @@ -420,6 +366,44 @@ chaz_CC_format_archiver_command(const char *target, const char *objects); char* chaz_CC_format_ranlib_command(const char *target); +/** Returns the filename for a shared library. + * + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the library without prefix and extension. + * @param version The library version. + */ +char* +chaz_CC_shared_lib_filename(const char *dir, const char *basename, + const char *version); + +/** Returns the filename for an import library. + * + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the library without prefix and extension. + * @param version The library version. + */ +char* +chaz_CC_import_lib_filename(const char *dir, const char *basename, + const char *version); + +/** Returns the filename for an MSVC export file. + * + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the library without prefix and extension. + * @param version The library version. + */ +char* +chaz_CC_export_filename(const char *dir, const char *basename, + const char *version); + +/** Returns the filename for a static library. + * + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the library without prefix and extension. + */ +char* +chaz_CC_static_lib_filename(const char *dir, const char *basename); + #endif /* H_CHAZ_COMPILER */ @@ -657,11 +641,11 @@ chaz_HeadCheck_contains_member(const char *struct_name, const char *member, #define H_CHAZ_MAKE /* #include "Charmonizer/Core/CFlags.h" */ -/* #include "Charmonizer/Core/Library.h" */ typedef struct chaz_MakeFile chaz_MakeFile; typedef struct chaz_MakeVar chaz_MakeVar; typedef struct chaz_MakeRule chaz_MakeRule; +typedef struct chaz_MakeBinary chaz_MakeBinary; typedef void (*chaz_Make_list_files_callback_t)(const char *dir, char *file, void *context); @@ -708,23 +692,21 @@ chaz_MakeFile_new(); /** MakeFile destructor. */ void -chaz_MakeFile_destroy(chaz_MakeFile *makefile); +chaz_MakeFile_destroy(chaz_MakeFile *self); /** 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, +chaz_MakeFile_add_var(chaz_MakeFile *self, 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 @@ -732,173 +714,174 @@ chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name, * @return a MakeRule. */ chaz_MakeRule* -chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target, +chaz_MakeFile_add_rule(chaz_MakeFile *self, const char *target, const char *prereq); /** Return the rule for the 'clean' target. - * - * @param makefile The makefile. */ chaz_MakeRule* -chaz_MakeFile_clean_rule(chaz_MakeFile *makefile); +chaz_MakeFile_clean_rule(chaz_MakeFile *self); /** Return the rule for the 'distclean' target. - * - * @param makefile The makefile. */ chaz_MakeRule* -chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile); +chaz_MakeFile_distclean_rule(chaz_MakeFile *self); -/** Add a rule to link an executable. The executable will also be added to the - * list of files to clean. +/** Add an executable. Returns a chaz_MakeBinary object. * - * @param makefile The makefile. - * @param exe The name of the executable. - * @param sources The list of source files. - * @param link_flags Additional link flags. + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the executable without extension. */ -chaz_MakeRule* -chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe, - const char *sources, chaz_CFlags *link_flags); - -/** Add a rule to compile and 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 sources The list of source files. - * @param cflags Additional compiler flags. - */ -chaz_MakeRule* -chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe, - const char *sources, chaz_CFlags *cflags); +chaz_MakeBinary* +chaz_MakeFile_add_exe(chaz_MakeFile *self, const char *dir, + const char *basename); -/** Add a rule to link a shared library. The shared library will also be added - * to the list of files to clean. +/** Add a shared library. The library will be built in the current directory. + * Returns a chaz_MakeBinary object. * - * @param makefile The makefile. - * @param lib The shared library. - * @param sources The list of source files. - * @param link_flags Additional link flags. - */ -chaz_MakeRule* -chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, chaz_Lib *lib, - const char *sources, chaz_CFlags *link_flags); - -/** Add a rule to create a static library. The static library will also be added - * to the list of files to clean. + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the library without prefix and extension. + * @param version The version of the library. + * @param major_version The major version of the library. + */ +chaz_MakeBinary* +chaz_MakeFile_add_shared_lib(chaz_MakeFile *self, const char *dir, + const char *basename, const char *version, + const char *major_version); + +/** Add a static library. The library will be built in the current directory. + * Returns a chaz_MakeBinary object. * - * @param makefile The makefile. - * @param lib The static library. - * @param objects The list of object files to be archived. + * @param dir The target directory or NULL for the current directory. + * @param basename The name of the library without prefix and extension. */ -chaz_MakeRule* -chaz_MakeFile_add_static_lib(chaz_MakeFile *makefile, chaz_Lib *lib, - const char *objects); +chaz_MakeBinary* +chaz_MakeFile_add_static_lib(chaz_MakeFile *self, const char *dir, + const char *basename); /** Add a rule to build the lemon parser generator. * - * @param makefile The makefile. * @param dir The lemon directory. */ -chaz_MakeRule* -chaz_MakeFile_add_lemon_exe(chaz_MakeFile *makefile, const char *dir); +chaz_MakeBinary* +chaz_MakeFile_add_lemon_exe(chaz_MakeFile *self, const char *dir); /** Add a rule for a lemon grammar. * - * @param makefile The makefile. * @param base_name The filename of the grammar without extension. */ chaz_MakeRule* -chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *makefile, - const char *base_name); - -/** Override compiler flags for a single object file. - * - * @param makefile The makefile. - * @param obj The object file. - * @param cflags Compiler flags. - */ -chaz_MakeRule* -chaz_MakeFile_override_cflags(chaz_MakeFile *makefile, const char *obj, - chaz_CFlags *cflags); +chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *self, const char *base_name); /** Write the makefile to a file named 'Makefile' in the current directory. - * - * @param makefile The makefile. */ void -chaz_MakeFile_write(chaz_MakeFile *makefile); +chaz_MakeFile_write(chaz_MakeFile *self); /** 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); +chaz_MakeVar_append(chaz_MakeVar *self, 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); +chaz_MakeRule_add_target(chaz_MakeRule *self, 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); +chaz_MakeRule_add_prereq(chaz_MakeRule *self, 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); +chaz_MakeRule_add_command(chaz_MakeRule *self, const char *command); /** Add a command to be executed with a special runtime library path. * - * @param rule The rule. * @param command The additional command. * @param ... NULL-terminated list of library directories. */ void -chaz_MakeRule_add_command_with_libpath(chaz_MakeRule *rule, +chaz_MakeRule_add_command_with_libpath(chaz_MakeRule *self, const char *command, ...); /** Add a command to remove one or more files. * - * @param rule The rule. * @param files The list of files. */ void -chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files); +chaz_MakeRule_add_rm_command(chaz_MakeRule *self, const char *files); /** Add a command to remove one or more directories. * - * @param rule The rule. * @param dirs The list of directories. */ void -chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs); +chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *self, const char *dirs); /** 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_make_command(chaz_MakeRule *rule, const char *dir, +chaz_MakeRule_add_make_command(chaz_MakeRule *self, const char *dir, const char *target); +/** Add a source file for the binary. + * + * @param dir The source directory or NULL for the current directory. + * @param filename The filename. + */ +void +chaz_MakeBinary_add_src_file(chaz_MakeBinary *self, const char *dir, + const char *filename); + +/** Add all .c files in a directory as sources for the binary. + * + * @param path The path to the directory. + */ +void +chaz_MakeBinary_add_src_dir(chaz_MakeBinary *self, const char *path); + +/** Add a prerequisite to the make rule of the binary. + * + * @param prereq The prerequisite. + */ +void +chaz_MakeBinary_add_prereq(chaz_MakeBinary *self, const char *prereq); + +/** Return a list of all objects separated by space. + */ +char* +chaz_MakeBinary_obj_string(chaz_MakeBinary *self); + +/** Accessor for target. + */ +const char* +chaz_MakeBinary_get_target(chaz_MakeBinary *self); + +/** Accessor for compile flags. + */ +chaz_CFlags* +chaz_MakeBinary_get_compile_flags(chaz_MakeBinary *self); + +/** Accessor for link flags. + */ +chaz_CFlags* +chaz_MakeBinary_get_link_flags(chaz_MakeBinary *self); + #endif /* H_CHAZ_MAKE */ @@ -1705,168 +1688,6 @@ void chaz_VariadicMacros_run(void); /***************************************************************************/ -#line 17 "src/Charmonizer/Core/Library.c" -#include <string.h> -#include <stdlib.h> -/* #include "Charmonizer/Core/Library.h" */ -/* #include "Charmonizer/Core/Compiler.h" */ -/* #include "Charmonizer/Core/Util.h" */ -/* #include "Charmonizer/Core/OperatingSystem.h" */ - -struct chaz_Lib { - char *name; - char *version; - char *major_version; - int is_static; - int is_shared; -}; - -static char* -S_build_filename(chaz_Lib *lib, const char *version, const char *ext); - -static const char* -S_get_prefix(chaz_Lib *lib); - -chaz_Lib* -chaz_Lib_new_shared(const char *name, const char *version, - const char *major_version) { - chaz_Lib *lib = (chaz_Lib*)malloc(sizeof(chaz_Lib)); - lib->name = chaz_Util_strdup(name); - lib->version = chaz_Util_strdup(version); - lib->major_version = chaz_Util_strdup(major_version); - lib->is_shared = 1; - lib->is_static = 0; - return lib; -} - -chaz_Lib* -chaz_Lib_new_static(const char *name) { - chaz_Lib *lib = (chaz_Lib*)malloc(sizeof(chaz_Lib)); - lib->name = chaz_Util_strdup(name); - lib->version = NULL; - lib->major_version = NULL; - lib->is_shared = 0; - lib->is_static = 1; - return lib; -} - -void -chaz_Lib_destroy(chaz_Lib *lib) { - free(lib->name); - free(lib->version); - free(lib->major_version); - free(lib); -} - -const char* -chaz_Lib_get_name(chaz_Lib *lib) { - return lib->name; -} - -const char* -chaz_Lib_get_version(chaz_Lib *lib) { - return lib->version; -} - -const char* -chaz_Lib_get_major_version(chaz_Lib *lib) { - return lib->major_version; -} - -int -chaz_Lib_is_shared (chaz_Lib *lib) { - return lib->is_shared; -} - -int -chaz_Lib_is_static (chaz_Lib *lib) { - return lib->is_static; -} - -char* -chaz_Lib_filename(chaz_Lib *lib) { - if (lib->is_static) { - return chaz_Lib_no_version_filename(lib); - } - else { - const char *ext = chaz_CC_shared_lib_ext(); - if (chaz_CC_binary_format() == CHAZ_CC_BINFMT_PE) { - return S_build_filename(lib, lib->major_version, ext); - } - else { - return S_build_filename(lib, lib->version, ext); - } - } -} - -char* -chaz_Lib_major_version_filename(chaz_Lib *lib) { - if (lib->is_static) { - return chaz_Lib_no_version_filename(lib); - } - else { - const char *ext = chaz_CC_shared_lib_ext(); - return S_build_filename(lib, lib->major_version, ext); - } -} - -char* -chaz_Lib_no_version_filename(chaz_Lib *lib) { - const char *prefix = S_get_prefix(lib); - const char *ext = lib->is_shared - ? chaz_CC_shared_lib_ext() - : chaz_CC_static_lib_ext(); - return chaz_Util_join("", prefix, lib->name, ext, NULL); -} - -char* -chaz_Lib_implib_filename(chaz_Lib *lib) { - const char *ext = chaz_CC_import_lib_ext(); - return S_build_filename(lib, lib->major_version, ext); -} - -char* -chaz_Lib_export_filename(chaz_Lib *lib) { - return S_build_filename(lib, lib->major_version, ".exp"); -} - -static char* -S_build_filename(chaz_Lib *lib, const char *version, const char *ext) { - const char *prefix = S_get_prefix(lib); - int binary_format = chaz_CC_binary_format(); - - if (binary_format == CHAZ_CC_BINFMT_PE) { - return chaz_Util_join("", prefix, lib->name, "-", version, ext, NULL); - } - else if (binary_format == CHAZ_CC_BINFMT_MACHO) { - return chaz_Util_join("", prefix, lib->name, ".", version, ext, NULL); - } - else if (binary_format == CHAZ_CC_BINFMT_ELF) { - return chaz_Util_join("", prefix, lib->name, ext, ".", version, NULL); - } - else { - chaz_Util_die("Unsupported binary format"); - return NULL; - } -} - -static const char* -S_get_prefix(chaz_Lib *lib) { - if (chaz_CC_msvc_version_num()) { - return ""; - } - else if (chaz_CC_is_cygwin()) { - return lib->is_static ? "lib" : "cyg"; - } - else { - return "lib"; - } -} - - - -/***************************************************************************/ - #line 17 "src/Charmonizer/Core/CFlags.c" #include <string.h> #include <stdlib.h> @@ -1874,7 +1695,6 @@ S_get_prefix(chaz_Lib *lib) { /* #include "Charmonizer/Core/Compiler.h" */ /* #include "Charmonizer/Core/Util.h" */ /* #include "Charmonizer/Core/OperatingSystem.h" */ -/* #include "Charmonizer/Core/Library.h" */ struct chaz_CFlags { int style; @@ -2098,55 +1918,44 @@ chaz_CFlags_hide_symbols(chaz_CFlags *flags) { } void -chaz_CFlags_link_shared_library(chaz_CFlags *flags) { - const char *string; +chaz_CFlags_link_shared_library(chaz_CFlags *flags, const char *basename, + const char *version, + const char *major_version) { + char *string = NULL; + if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) { - string = "/DLL"; + string = chaz_Util_strdup("/DLL"); } else if (flags->style == CHAZ_CFLAGS_STYLE_GNU) { - if (chaz_CC_binary_format() == CHAZ_CC_BINFMT_MACHO) { - string = "-dynamiclib"; + int binary_format = chaz_CC_binary_format(); + + if (binary_format == CHAZ_CC_BINFMT_MACHO) { + string = chaz_Util_join(" ", "-dynamiclib", "-current_version", + version, "-compatibility_version", + major_version, NULL); } - else { - string = "-shared"; + else if (binary_format == CHAZ_CC_BINFMT_ELF) { + string = chaz_Util_join("", "-shared -Wl,-soname,lib", basename, + ".so.", major_version, NULL); + } + else if (binary_format == CHAZ_CC_BINFMT_PE) { + string = chaz_Util_join("", "-shared -Wl,--out-implib,lib", + basename, "-", major_version, ".dll.a", + NULL); } } else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) { - string = "-G"; + string = chaz_Util_join("", "-G -h lib", basename, ".so.", + major_version, NULL); } else { chaz_Util_die("Don't know how to link a shared library with '%s'", chaz_CC_get_cc()); } - chaz_CFlags_append(flags, string); -} - -void -chaz_CFlags_set_shared_library_version(chaz_CFlags *flags, chaz_Lib *lib) { - if (flags->style == CHAZ_CFLAGS_STYLE_GNU) { - int binary_format = chaz_CC_binary_format(); - if (binary_format == CHAZ_CC_BINFMT_MACHO) { - const char *version = chaz_Lib_get_version(lib); - char *string - = chaz_Util_join(" ", "-current_version", version, NULL); - chaz_CFlags_append(flags, string); - free(string); - } - else if (binary_format == CHAZ_CC_BINFMT_ELF) { - char *soname = chaz_Lib_major_version_filename(lib); - char *string = chaz_Util_join("", "-Wl,-soname,", soname, NULL); - chaz_CFlags_append(flags, string); - free(string); - free(soname); - } - } - else if (flags->style == CHAZ_CFLAGS_STYLE_SUN_C) { - char *soname = chaz_Lib_major_version_filename(lib); - char *string = chaz_Util_join(" ", "-h", soname, NULL); + if (string) { chaz_CFlags_append(flags, string); free(string); - free(soname); } } @@ -2187,20 +1996,22 @@ chaz_CFlags_add_library_path(chaz_CFlags *flags, const char *directory) { } void -chaz_CFlags_add_library(chaz_CFlags *flags, chaz_Lib *lib) { +chaz_CFlags_add_shared_lib(chaz_CFlags *flags, const char *dir, + const char *basename, const char *major_version) { + int binfmt = chaz_CC_binary_format(); char *filename; - if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) { - filename = chaz_Lib_implib_filename(lib); + if (binfmt == CHAZ_CC_BINFMT_PE) { + filename = chaz_CC_import_lib_filename(dir, basename, major_version); } else { - filename = chaz_Lib_filename(lib); + filename = chaz_CC_shared_lib_filename(dir, basename, major_version); } chaz_CFlags_append(flags, filename); free(filename); } void -chaz_CFlags_add_external_library(chaz_CFlags *flags, const char *library) { +chaz_CFlags_add_external_lib(chaz_CFlags *flags, const char *library) { char *string; if (flags->style == CHAZ_CFLAGS_STYLE_MSVC) { string = chaz_Util_join("", library, ".lib", NULL); @@ -2256,6 +2067,7 @@ struct chaz_CLI { static void S_chaz_CLI_error(chaz_CLI *self, const char *pattern, ...) { va_list ap; + (void)self; if (chaz_Util_verbosity > 0) { va_start(ap, pattern); vfprintf(stderr, pattern, ap); @@ -2349,7 +2161,7 @@ S_chaz_CLI_rebuild_help(chaz_CLI *self) { } static chaz_CLIOption* -S_find_opt(chaz_CLI *self, const char *name) { +S_chaz_CLI_find_opt(chaz_CLI *self, const char *name) { int i; for (i = 0; i < self->num_opts; i++) { chaz_CLIOption *opt = &self->opts[i]; @@ -2445,7 +2257,7 @@ chaz_CLI_register(chaz_CLI *self, const char *name, const char *help, int chaz_CLI_set(chaz_CLI *self, const char *name, const char *value) { - chaz_CLIOption *opt = S_find_opt(self, name); + chaz_CLIOption *opt = S_chaz_CLI_find_opt(self, name); if (opt == NULL) { S_chaz_CLI_error(self, "Attempt to set unknown option: '%s'", name); return 0; @@ -2473,7 +2285,7 @@ chaz_CLI_set(chaz_CLI *self, const char *name, const char *value) { int chaz_CLI_unset(chaz_CLI *self, const char *name) { - chaz_CLIOption *opt = S_find_opt(self, name); + chaz_CLIOption *opt = S_chaz_CLI_find_opt(self, name); if (opt == NULL) { S_chaz_CLI_error(self, "Attempt to unset unknown option: '%s'", name); return 0; @@ -2486,7 +2298,7 @@ chaz_CLI_unset(chaz_CLI *self, const char *name) { int chaz_CLI_defined(chaz_CLI *self, const char *name) { - chaz_CLIOption *opt = S_find_opt(self, name); + chaz_CLIOption *opt = S_chaz_CLI_find_opt(self, name); if (opt == NULL) { S_chaz_CLI_error(self, "Inquiry for unknown option: '%s'", name); return 0; @@ -2496,7 +2308,7 @@ chaz_CLI_defined(chaz_CLI *self, const char *name) { long chaz_CLI_longval(chaz_CLI *self, const char *name) { - chaz_CLIOption *opt = S_find_opt(self, name); + chaz_CLIOption *opt = S_chaz_CLI_find_opt(self, name); if (opt == NULL) { S_chaz_CLI_error(self, "Longval request for unknown option: '%s'", name); @@ -2510,7 +2322,7 @@ chaz_CLI_longval(chaz_CLI *self, const char *name) { const char* chaz_CLI_strval(chaz_CLI *self, const char *name) { - chaz_CLIOption *opt = S_find_opt(self, name); + chaz_CLIOption *opt = S_chaz_CLI_find_opt(self, name); if (opt == NULL) { S_chaz_CLI_error(self, "Strval request for unknown option: '%s'", name); @@ -2571,7 +2383,7 @@ chaz_CLI_parse(chaz_CLI *self, int argc, const char *argv[]) { if (value == NULL && i + 1 < argc) { /* Support both '--opt=val' and '--opt val' styles. */ - chaz_CLIOption *opt = S_find_opt(self, name); + chaz_CLIOption *opt = S_chaz_CLI_find_opt(self, name); if (opt == NULL) { S_chaz_CLI_error(self, "Attempt to set unknown option: '%s'", name); @@ -2631,6 +2443,13 @@ chaz_CC_eval_macro(const char *macro); static void chaz_CC_detect_known_compilers(void); +/** Build a library filename from its components. + */ +static char* +chaz_CC_build_lib_filename(const char *dir, const char *prefix, + const char *basename, const char *version, + const char *ext); + /* Temporary files. */ #define CHAZ_CC_TRY_SOURCE_PATH "_charmonizer_try.c" #define CHAZ_CC_TRY_BASENAME "_charmonizer_try" @@ -2656,12 +2475,13 @@ static struct { int intval___clang__; int intval___SUNPRO_C; int is_cygwin; + int is_mingw; chaz_CFlags *extra_cflags; chaz_CFlags *temp_cflags; } chaz_CC = { NULL, NULL, NULL, "", "", "", "", "", "", - 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }; @@ -2669,7 +2489,6 @@ void chaz_CC_init(const char *compiler_command, const char *compiler_flags) { const char *code = "int main() { return 0; }\n"; int compile_succeeded = 0; - int retval = -1; if (chaz_Util_verbosity) { printf("Creating compiler object...\n"); } @@ -2771,6 +2590,9 @@ chaz_CC_init(const char *compiler_command, const char *compiler_flags) { if (chaz_CC_has_macro("__CYGWIN__")) { chaz_CC.is_cygwin = 1; } + if (chaz_CC_has_macro("__MINGW32__")) { + chaz_CC.is_mingw = 1; + } } else { chaz_Util_die("Failed to detect binary format"); @@ -3144,6 +2966,11 @@ chaz_CC_is_cygwin(void) { return chaz_CC.is_cygwin; } +int +chaz_CC_is_mingw(void) { + return chaz_CC.is_mingw; +} + const char* chaz_CC_link_command() { if (chaz_CC.intval__MSC_VER) { @@ -3160,7 +2987,8 @@ chaz_CC_format_archiver_command(const char *target, const char *objects) { /* TODO: Write `objects` to a temporary file in order to avoid * exceeding line length limits. */ char *out = chaz_Util_join("", "/OUT:", target, NULL); - char *command = chaz_Util_join(" ", "lib", "/NOLOGO", out, NULL); + char *command = chaz_Util_join(" ", "lib", "/NOLOGO", objects, out, + NULL); free(out); return command; } @@ -3177,6 +3005,88 @@ chaz_CC_format_ranlib_command(const char *target) { return chaz_Util_join(" ", "ranlib", target, NULL); } +char* +chaz_CC_shared_lib_filename(const char *dir, const char *basename, + const char *version) { + /* Cygwin uses a "cyg" prefix for shared libraries. */ + const char *prefix = chaz_CC_msvc_version_num() + ? "" + : chaz_CC_is_cygwin() ? "cyg" : "lib"; + return chaz_CC_build_lib_filename(dir, prefix, basename, version, + chaz_CC.shared_lib_ext); +} + +char* +chaz_CC_import_lib_filename(const char *dir, const char *basename, + const char *version) { + const char *prefix = chaz_CC_msvc_version_num() ? "" : "lib"; + return chaz_CC_build_lib_filename(dir, prefix, basename, version, + chaz_CC.import_lib_ext); +} + +char* +chaz_CC_export_filename(const char *dir, const char *basename, + const char *version) { + /* Only for MSVC. */ + return chaz_CC_build_lib_filename(dir, "", basename, version, ".exp"); +} + +static char* +chaz_CC_build_lib_filename(const char *dir, const char *prefix, + const char *basename, const char *version, + const char *ext) { + char *suffix; + char *retval; + + if (version == NULL) { + suffix = chaz_Util_strdup(ext); + } + else { + int binary_format = chaz_CC_binary_format(); + + if (binary_format == CHAZ_CC_BINFMT_PE) { + suffix = chaz_Util_join("", "-", version, ext, NULL); + } + else if (binary_format == CHAZ_CC_BINFMT_MACHO) { + suffix = chaz_Util_join("", ".", version, ext, NULL); + } + else if (binary_format == CHAZ_CC_BINFMT_ELF) { + suffix = chaz_Util_join("", ext, ".", version, NULL); + } + else { + chaz_Util_die("Unsupported binary format"); + return NULL; + } + } + + if (dir == NULL || strcmp(dir, ".") == 0) { + retval = chaz_Util_join("", prefix, basename, suffix, NULL); + } + else { + const char *dir_sep = chaz_OS_dir_sep(); + retval = chaz_Util_join("", dir, dir_sep, prefix, basename, suffix, + NULL); + } + + free(suffix); + return retval; +} + +char* +chaz_CC_static_lib_filename(const char *dir, const char *basename) { + const char *prefix = chaz_CC_msvc_version_num() ? "" : "lib"; + + if (dir == NULL || strcmp(dir, ".") == 0) { + return chaz_Util_join("", prefix, basename, chaz_CC.static_lib_ext, + NULL); + } + else { + const char *dir_sep = chaz_OS_dir_sep(); + return chaz_Util_join("", dir, dir_sep, prefix, basename, + chaz_CC.static_lib_ext, NULL); + } +} + /***************************************************************************/ @@ -3329,7 +3239,7 @@ static struct { chaz_ConfElem *defs; size_t def_cap; size_t def_count; -} chaz_ConfWriterC = { NULL, NULL, 0, 0 }; +} chaz_ConfWriterC = { NULL, NULL, NULL, 0, 0 }; static chaz_ConfWriter CWC_conf_writer; /* Open the charmony.h file handle. Print supplied text to it, if non-null. @@ -4566,10 +4476,15 @@ chaz_HeadCheck_maybe_add_to_cache(const char *header_name, int exists) { #include <stdlib.h> #include <string.h> /* #include "Charmonizer/Core/Make.h" */ +/* #include "Charmonizer/Core/CFlags.h" */ /* #include "Charmonizer/Core/Compiler.h" */ /* #include "Charmonizer/Core/OperatingSystem.h" */ /* #include "Charmonizer/Core/Util.h" */ +#define CHAZ_MAKEBINARY_EXE 1 +#define CHAZ_MAKEBINARY_STATIC_LIB 2 +#define CHAZ_MAKEBINARY_SHARED_LIB 3 + struct chaz_MakeVar { char *name; char *value; @@ -4582,13 +4497,34 @@ struct chaz_MakeRule { char *commands; }; +struct chaz_MakeBinary { + int type; + char *target_dir; + char *basename; + char *version; + char *major_version; + char **sources; /* List of all sources. */ + size_t num_sources; + char **single_sources; /* Only sources from add_src_file. */ + size_t num_single_sources; + char **dirs; + size_t num_dirs; + chaz_MakeVar *obj_var; /* Owned by MakeFile. */ + char *dollar_var; + chaz_MakeRule *rule; /* Not added to MakeFile, owned by MakeBinary. */ + chaz_CFlags *compile_flags; + chaz_CFlags *link_flags; +}; + struct chaz_MakeFile { - chaz_MakeVar **vars; - size_t num_vars; - chaz_MakeRule **rules; - size_t num_rules; - chaz_MakeRule *clean; - chaz_MakeRule *distclean; + chaz_MakeVar **vars; + size_t num_vars; + chaz_MakeRule **rules; + size_t num_rules; + chaz_MakeRule *clean; + chaz_MakeRule *distclean; + chaz_MakeBinary **binaries; + size_t num_binaries; }; /* Static vars. */ @@ -4612,33 +4548,89 @@ static struct { * dmake */ static int -chaz_Make_detect(const char *make1, ...); +S_chaz_Make_detect(const char *make1, ...); static int -chaz_Make_audition(const char *make); +S_chaz_Make_audition(const char *make); -static chaz_MakeRule* -S_new_rule(const char *target, const char *prereq); +static void +S_chaz_MakeFile_finish_exe(chaz_MakeFile *self, chaz_MakeBinary *binary); static void -S_destroy_rule(chaz_MakeRule *rule); +S_chaz_MakeFile_finish_shared_lib(chaz_MakeFile *self, + chaz_MakeBinary *binary); static void -S_write_rule(chaz_MakeRule *rule, FILE *out); +S_chaz_MakeFile_finish_static_lib(chaz_MakeFile *self, + chaz_MakeBinary *binary); -void -chaz_Make_init(const char *make_command) { - chaz_Make.shell_type = chaz_OS_shell_type(); +static chaz_MakeBinary* +S_chaz_MakeFile_add_binary(chaz_MakeFile *self, int type, const char *dir, + const char *basename, const char *target); - if (make_command) { - if (!chaz_Make_detect(make_command, NULL)) { - chaz_Util_warn("Make utility '%s' doesn't appear to work"); - } - } +static void +S_chaz_MakeFile_write_binary_rules(chaz_MakeFile *self, + chaz_MakeBinary *binary, FILE *out); + +static void +S_chaz_MakeFile_write_object_rules(char **sources, const char *command, + FILE *out); + +static void +S_chaz_MakeFile_write_pattern_rules(char **dirs, const char *command, + FILE *out); + +static chaz_MakeRule* +S_chaz_MakeRule_new(const char *target, const char *prereq); + +static void +S_chaz_MakeRule_destroy(chaz_MakeRule *self); + +static void +S_chaz_MakeRule_write(chaz_MakeRule *self, FILE *out); + +static void +S_chaz_MakeBinary_destroy(chaz_MakeBinary *self); + +static void +S_chaz_MakeBinary_list_files_callback(const char *dir, char *file, + void *context); +static void +S_chaz_MakeBinary_do_add_src_file(chaz_MakeBinary *self, const char *path); + +/** Return the path to the object file for a source file. + * + * @param path The path to the source file. + */ +static char* +S_chaz_MakeBinary_obj_path(const char *src_path); + +void +chaz_Make_init(const char *make_command) { + chaz_Make.shell_type = chaz_OS_shell_type(); + + if (make_command) { + if (!S_chaz_Make_detect(make_command, NULL)) { + chaz_Util_warn("Make utility '%s' doesn't appear to work", + make_command); + } + } else { - if (!chaz_Make_detect("make", "gmake", "nmake", "dmake", - "mingw32-make", "mingw64-make", NULL) - ) { + int succeeded = 0; + + /* mingw32-make seems to try to run commands under both cmd.exe + * and sh.exe. Not sure about dmake. + */ + if (chaz_Make.shell_type == CHAZ_OS_POSIX) { + succeeded = S_chaz_Make_detect("make", "gmake", "dmake", + "mingw32-make", NULL); + } + else if (chaz_Make.shell_type == CHAZ_OS_CMD_EXE) { + succeeded = S_chaz_Make_detect("nmake", "dmake", "mingw32-make", + NULL); + } + + if (!succeeded) { chaz_Util_warn("No working make utility found"); } else if (chaz_Util_verbosity) { @@ -4663,18 +4655,18 @@ chaz_Make_shell_type(void) { } static int -chaz_Make_detect(const char *make1, ...) { +S_chaz_Make_detect(const char *make1, ...) { va_list args; const char *candidate; int found = 0; - const char makefile_content[] = "foo:\n\techo foo\\^bar\n"; + const char makefile_content[] = "foo:\n\t@echo 643490c943525d19\n"; chaz_Util_write_file("_charm_Makefile", makefile_content); /* Audition candidates. */ - found = chaz_Make_audition(make1); + found = S_chaz_Make_audition(make1); va_start(args, make1); while (!found && (NULL != (candidate = va_arg(args, const char*)))) { - found = chaz_Make_audition(candidate); + found = S_chaz_Make_audition(candidate); } va_end(args); @@ -4684,7 +4676,7 @@ chaz_Make_detect(const char *make1, ...) { } static int -chaz_Make_audition(const char *make) { +S_chaz_Make_audition(const char *make) { int succeeded = 0; char *command = chaz_Util_join(" ", make, "-f", "_charm_Makefile", NULL); @@ -4693,15 +4685,8 @@ chaz_Make_audition(const char *make) { 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\\bar")) { - if (chaz_Make.shell_type == CHAZ_OS_CMD_EXE) { - succeeded = 1; - } - } - else if (NULL != strstr(content, "foo^bar")) { - if (chaz_Make.shell_type == CHAZ_OS_POSIX) { - succeeded = 1; - } + if (content != NULL && strstr(content, "643490c943525d19") != NULL) { + succeeded = 1; } free(content); } @@ -4717,59 +4702,60 @@ chaz_Make_audition(const char *make) { chaz_MakeFile* chaz_MakeFile_new() { - chaz_MakeFile *makefile = (chaz_MakeFile*)malloc(sizeof(chaz_MakeFile)); + chaz_MakeFile *self = (chaz_MakeFile*)calloc(1, sizeof(chaz_MakeFile)); const char *exe_ext = chaz_CC_exe_ext(); const char *obj_ext = chaz_CC_obj_ext(); char *generated; - 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; + self->vars = (chaz_MakeVar**)calloc(1, sizeof(chaz_MakeVar*)); + self->rules = (chaz_MakeRule**)calloc(1, sizeof(chaz_MakeRule*)); + self->binaries = (chaz_MakeBinary**)calloc(1, sizeof(chaz_MakeBinary*)); - makefile->clean = S_new_rule("clean", NULL); - makefile->distclean = S_new_rule("distclean", "clean"); + self->clean = S_chaz_MakeRule_new("clean", NULL); + self->distclean = S_chaz_MakeRule_new("distclean", "clean"); generated = chaz_Util_join("", "charmonizer", exe_ext, " charmonizer", obj_ext, " charmony.h Makefile", NULL); - chaz_MakeRule_add_rm_command(makefile->distclean, generated); + chaz_MakeRule_add_rm_command(self->distclean, generated); free(generated); - return makefile; + return self; } void -chaz_MakeFile_destroy(chaz_MakeFile *makefile) { +chaz_MakeFile_destroy(chaz_MakeFile *self) { size_t i; - for (i = 0; makefile->vars[i]; i++) { - chaz_MakeVar *var = makefile->vars[i]; + for (i = 0; self->vars[i]; i++) { + chaz_MakeVar *var = self->vars[i]; free(var->name); free(var->value); free(var); } - free(makefile->vars); + free(self->vars); + + for (i = 0; self->rules[i]; i++) { + S_chaz_MakeRule_destroy(self->rules[i]); + } + free(self->rules); - for (i = 0; makefile->rules[i]; i++) { - S_destroy_rule(makefile->rules[i]); + for (i = 0; self->binaries[i]; i++) { + S_chaz_MakeBinary_destroy(self->binaries[i]); } - free(makefile->rules); + free(self->binaries); - S_destroy_rule(makefile->clean); - S_destroy_rule(makefile->distclean); + S_chaz_MakeRule_destroy(self->clean); + S_chaz_MakeRule_destroy(self->distclean); - free(makefile); + free(self); } chaz_MakeVar* -chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name, +chaz_MakeFile_add_var(chaz_MakeFile *self, 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; + chaz_MakeVar **vars = self->vars; + size_t num_vars = self->num_vars + 1; var->name = chaz_Util_strdup(name); var->value = chaz_Util_strdup(""); @@ -4781,241 +4767,303 @@ chaz_MakeFile_add_var(chaz_MakeFile *makefile, const char *name, (num_vars + 1) * sizeof(chaz_MakeVar*)); vars[num_vars-1] = var; vars[num_vars] = NULL; - makefile->vars = vars; - makefile->num_vars = num_vars; + self->vars = vars; + self->num_vars = num_vars; return var; } chaz_MakeRule* -chaz_MakeFile_add_rule(chaz_MakeFile *makefile, const char *target, +chaz_MakeFile_add_rule(chaz_MakeFile *self, const char *target, const char *prereq) { - chaz_MakeRule *rule = S_new_rule(target, prereq); - chaz_MakeRule **rules = makefile->rules; - size_t num_rules = makefile->num_rules + 1; + chaz_MakeRule *rule = S_chaz_MakeRule_new(target, prereq); + chaz_MakeRule **rules = self->rules; + size_t num_rules = self->num_rules + 1; 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; + self->rules = rules; + self->num_rules = num_rules; return rule; } chaz_MakeRule* -chaz_MakeFile_clean_rule(chaz_MakeFile *makefile) { - return makefile->clean; +chaz_MakeFile_clean_rule(chaz_MakeFile *self) { + return self->clean; } chaz_MakeRule* -chaz_MakeFile_distclean_rule(chaz_MakeFile *makefile) { - return makefile->distclean; +chaz_MakeFile_distclean_rule(chaz_MakeFile *self) { + return self->distclean; } -chaz_MakeRule* -chaz_MakeFile_add_exe(chaz_MakeFile *makefile, const char *exe, - const char *sources, chaz_CFlags *link_flags) { - chaz_CFlags *local_flags = chaz_CC_new_cflags(); - const char *link = chaz_CC_link_command(); - const char *link_flags_string = ""; - const char *local_flags_string; - chaz_MakeRule *rule; - char *command; - - rule = chaz_MakeFile_add_rule(makefile, exe, sources); +chaz_MakeBinary* +chaz_MakeFile_add_exe(chaz_MakeFile *self, const char *dir, + const char *basename) { + const char *exe_ext = chaz_CC_exe_ext(); + char *target; + chaz_MakeBinary *binary; - if (link_flags) { - link_flags_string = chaz_CFlags_get_string(link_flags); + if (dir == NULL || strcmp(dir, ".") == 0) { + target = chaz_Util_join("", basename, exe_ext, NULL); } - if (chaz_CC_msvc_version_num()) { - chaz_CFlags_append(local_flags, "/nologo"); + else { + const char *dir_sep = chaz_OS_dir_sep(); + target = chaz_Util_join("", dir, dir_sep, basename, exe_ext, NULL); } - chaz_CFlags_set_link_output(local_flags, exe); - local_flags_string = chaz_CFlags_get_string(local_flags); - command = chaz_Util_join(" ", link, sources, link_flags_string, - local_flags_string, NULL); - chaz_MakeRule_add_command(rule, command); - chaz_MakeRule_add_rm_command(makefile->clean, exe); + binary = S_chaz_MakeFile_add_binary(self, CHAZ_MAKEBINARY_EXE, dir, + basename, target); - chaz_CFlags_destroy(local_flags); - free(command); - return rule; + free(target); + return binary; } -chaz_MakeRule* -chaz_MakeFile_add_compiled_exe(chaz_MakeFile *makefile, const char *exe, - const char *sources, chaz_CFlags *cflags) { - chaz_CFlags *local_flags = chaz_CC_new_cflags(); - const char *cc = chaz_CC_get_cc(); - const char *cflags_string = ""; - const char *local_flags_string; - chaz_MakeRule *rule; - char *command; +void +S_chaz_MakeFile_finish_exe(chaz_MakeFile *self, chaz_MakeBinary *binary) { + const char *link = chaz_CC_link_command(); + const char *link_flags_string; + char *command; + + (void)self; + + /* This is destructive but shouldn't be a problem since a Makefile + * is only written once. + */ + chaz_CFlags_set_link_output(binary->link_flags, "$@"); + link_flags_string = chaz_CFlags_get_string(binary->link_flags); + + /* Objects in dollar var must come before flags since flags may + * contain libraries. + */ + command = chaz_Util_join(" ", link, binary->dollar_var, link_flags_string, + NULL); + chaz_MakeRule_add_command(binary->rule, command); + free(command); +} - rule = chaz_MakeFile_add_rule(makefile, exe, sources); +chaz_MakeBinary* +chaz_MakeFile_add_shared_lib(chaz_MakeFile *self, const char *dir, + const char *basename, const char *version, + const char *major_version) { + int binary_format = chaz_CC_binary_format(); + char *target; + chaz_MakeBinary *binary; - if (cflags) { - cflags_string = chaz_CFlags_get_string(cflags); + if (binary_format == CHAZ_CC_BINFMT_PE) { + target = chaz_CC_shared_lib_filename(dir, basename, major_version); } - if (chaz_CC_msvc_version_num()) { - chaz_CFlags_append(local_flags, "/nologo"); + else { + target = chaz_CC_shared_lib_filename(dir, basename, version); } - chaz_CFlags_set_output_exe(local_flags, exe); - local_flags_string = chaz_CFlags_get_string(local_flags); - command = chaz_Util_join(" ", cc, sources, cflags_string, - local_flags_string, NULL); - chaz_MakeRule_add_command(rule, command); - chaz_MakeRule_add_rm_command(makefile->clean, exe); - /* TODO: Clean .obj file on Windows. */ + binary = S_chaz_MakeFile_add_binary(self, CHAZ_MAKEBINARY_SHARED_LIB, dir, + basename, target); + binary->version = chaz_Util_strdup(version); + binary->major_version = chaz_Util_strdup(major_version); - chaz_CFlags_destroy(local_flags); - free(command); - return rule; + chaz_CFlags_compile_shared_library(binary->compile_flags); + chaz_CFlags_link_shared_library(binary->link_flags, basename, version, + major_version); + + free(target); + return binary; } -chaz_MakeRule* -chaz_MakeFile_add_shared_lib(chaz_MakeFile *makefile, chaz_Lib *lib, - const char *sources, chaz_CFlags *link_flags) { - chaz_CFlags *local_flags = chaz_CC_new_cflags(); +void +S_chaz_MakeFile_finish_shared_lib(chaz_MakeFile *self, + chaz_MakeBinary *binary) { const char *link = chaz_CC_link_command(); - const char *link_flags_string = ""; - const char *local_flags_string; + const char *link_flags_string; int binfmt = chaz_CC_binary_format(); - chaz_MakeRule *rule; - char *filename; + char *no_v_name + = chaz_CC_shared_lib_filename(binary->target_dir, binary->basename, + NULL); + char *major_v_name + = chaz_CC_shared_lib_filename(binary->target_dir, binary->basename, + binary->major_version); char *command; - filename = chaz_Lib_filename(lib); - rule = chaz_MakeFile_add_rule(makefile, filename, sources); - - if (link_flags) { - link_flags_string = chaz_CFlags_get_string(link_flags); - } - - if (chaz_CC_msvc_version_num()) { - chaz_CFlags_append(local_flags, "/nologo"); - } - chaz_CFlags_link_shared_library(local_flags); if (binfmt == CHAZ_CC_BINFMT_MACHO) { - /* Set temporary install name with full path on Darwin. */ const char *dir_sep = chaz_OS_dir_sep(); - char *major_v_name = chaz_Lib_major_version_filename(lib); - char *install_name = chaz_Util_join("", "-install_name $(CURDIR)", - dir_sep, major_v_name, NULL); - chaz_CFlags_append(local_flags, install_name); - free(major_v_name); + char *install_name; + + /* Set temporary install name with full path on Darwin. */ + install_name = chaz_Util_join("", "-install_name $(CURDIR)", dir_sep, + major_v_name, NULL); + chaz_CFlags_append(binary->link_flags, install_name); free(install_name); } - chaz_CFlags_set_shared_library_version(local_flags, lib); - chaz_CFlags_set_link_output(local_flags, filename); - local_flags_string = chaz_CFlags_get_string(local_flags); - command = chaz_Util_join(" ", link, sources, link_flags_string, - local_flags_string, NULL); - chaz_MakeRule_add_command(rule, command); - free(command); + chaz_CFlags_set_link_output(binary->link_flags, "$@"); + link_flags_string = chaz_CFlags_get_string(binary->link_flags); - chaz_MakeRule_add_rm_command(makefile->clean, filename); + command = chaz_Util_join(" ", link, binary->dollar_var, link_flags_string, + NULL); + chaz_MakeRule_add_command(binary->rule, command); + free(command); /* Add symlinks. */ if (binfmt == CHAZ_CC_BINFMT_ELF || binfmt == CHAZ_CC_BINFMT_MACHO) { - char *major_v_name = chaz_Lib_major_version_filename(lib); - char *no_v_name = chaz_Lib_no_version_filename(lib); - - command = chaz_Util_join(" ", "ln -sf", filename, major_v_name, NULL); - chaz_MakeRule_add_command(rule, command); + command = chaz_Util_join(" ", "ln -sf", binary->rule->targets, + major_v_name, NULL); + chaz_MakeRule_add_command(binary->rule, command); free(command); if (binfmt == CHAZ_CC_BINFMT_MACHO) { - command = chaz_Util_join(" ", "ln -sf", filename, no_v_name, - NULL); + command = chaz_Util_join(" ", "ln -sf", binary->rule->targets, + no_v_name, NULL); } else { command = chaz_Util_join(" ", "ln -sf", major_v_name, no_v_name, NULL); } - chaz_MakeRule_add_command(rule, command); + chaz_MakeRule_add_command(binary->rule, command); free(command); - chaz_MakeRule_add_rm_command(makefile->clean, major_v_name); - chaz_MakeRule_add_rm_command(makefile->clean, no_v_name); + chaz_MakeRule_add_rm_command(self->clean, major_v_name); + chaz_MakeRule_add_rm_command(self->clean, no_v_name); + } - free(major_v_name); - free(no_v_name); + if (binfmt == CHAZ_CC_BINFMT_PE) { + /* Remove import library. */ + char *filename + = chaz_CC_import_lib_filename(binary->target_dir, binary->basename, + binary->major_version); + chaz_MakeRule_add_rm_command(self->clean, filename); + free(filename); } if (chaz_CC_msvc_version_num()) { - /* Remove import library and export file under MSVC. */ - char *lib_filename = chaz_Lib_implib_filename(lib); - char *exp_filename = chaz_Lib_export_filename(lib); - chaz_MakeRule_add_rm_command(makefile->clean, lib_filename); - chaz_MakeRule_add_rm_command(makefile->clean, exp_filename); - free(lib_filename); - free(exp_filename); + /* Remove export file. */ + char *filename + = chaz_CC_export_filename(binary->target_dir, binary->basename, + binary->major_version); + chaz_MakeRule_add_rm_command(self->clean, filename); + free(filename); } - chaz_CFlags_destroy(local_flags); - free(filename); - return rule; + free(major_v_name); + free(no_v_name); } -chaz_MakeRule* -chaz_MakeFile_add_static_lib(chaz_MakeFile *makefile, chaz_Lib *lib, - const char *objects) { - chaz_MakeRule *rule; - char *filename; - char *command; - - filename = chaz_Lib_filename(lib); - rule = chaz_MakeFile_add_rule(makefile, filename, objects); - command = chaz_CC_format_archiver_command(filename, objects); - chaz_MakeRule_add_command(rule, command); +chaz_MakeBinary* +chaz_MakeFile_add_static_lib(chaz_MakeFile *self, const char *dir, + const char *basename) { + char *target = chaz_CC_static_lib_filename(dir, basename); + chaz_MakeBinary *binary + = S_chaz_MakeFile_add_binary(self, CHAZ_MAKEBINARY_STATIC_LIB, dir, + basename, target); + + free(target); + return binary; +} + +static void +S_chaz_MakeFile_finish_static_lib(chaz_MakeFile *self, + chaz_MakeBinary *binary) { + char *command; + + (void)self; + + command = chaz_CC_format_archiver_command("$@", binary->dollar_var); + chaz_MakeRule_add_command(binary->rule, command); free(command); - command = chaz_CC_format_ranlib_command(filename); + + command = chaz_CC_format_ranlib_command("$@"); if (command) { - chaz_MakeRule_add_command(rule, command); + chaz_MakeRule_add_command(binary->rule, command); free(command); } - chaz_MakeRule_add_rm_command(makefile->clean, filename); - - free(filename); - return rule; } -chaz_MakeRule* -chaz_MakeFile_add_lemon_exe(chaz_MakeFile *makefile, const char *dir) { - chaz_CFlags *cflags = chaz_CC_new_cflags(); - chaz_MakeRule *rule; - const char *dir_sep = chaz_OS_dir_sep(); - const char *exe_ext = chaz_CC_exe_ext(); - char *lemon_exe = chaz_Util_join("", dir, dir_sep, "lemon", exe_ext, NULL); - char *lemon_c = chaz_Util_join(dir_sep, dir, "lemon.c", NULL); +static chaz_MakeBinary* +S_chaz_MakeFile_add_binary(chaz_MakeFile *self, int type, const char *dir, + const char *basename, const char *target) { + chaz_MakeBinary *binary + = (chaz_MakeBinary*)calloc(1, sizeof(chaz_MakeBinary)); + const char *suffix; + char *uc_basename = chaz_Util_strdup(basename); + char *binary_var_name; + char *obj_var_name; + char *dollar_var; + size_t i; + size_t num_binaries; + size_t alloc_size; + chaz_MakeBinary **binaries; + + switch (type) { + case CHAZ_MAKEBINARY_EXE: suffix = "EXE"; break; + case CHAZ_MAKEBINARY_STATIC_LIB: suffix = "STATIC_LIB"; break; + case CHAZ_MAKEBINARY_SHARED_LIB: suffix = "SHARED_LIB"; break; + default: + chaz_Util_die("Unknown binary type %d", type); + return NULL; + } + + for (i = 0; uc_basename[i] != '\0'; i++) { + uc_basename[i] = toupper((unsigned char)uc_basename[i]); + } + + binary_var_name = chaz_Util_join("_", uc_basename, suffix, NULL); + obj_var_name = chaz_Util_join("_", uc_basename, suffix, "OBJS", NULL); + dollar_var = chaz_Util_join("", "$(", obj_var_name, ")", NULL); + + chaz_MakeFile_add_var(self, binary_var_name, target); + + binary->type = type; + binary->target_dir = dir ? chaz_Util_strdup(dir) : NULL; + binary->basename = chaz_Util_strdup(basename); + binary->obj_var = chaz_MakeFile_add_var(self, obj_var_name, NULL); + binary->dollar_var = dollar_var; + binary->rule = S_chaz_MakeRule_new(target, dollar_var); + binary->sources = (char**)calloc(1, sizeof(char*)); + binary->single_sources = (char**)calloc(1, sizeof(char*)); + binary->dirs = (char**)calloc(1, sizeof(char*)); + binary->compile_flags = chaz_CC_new_cflags(); + binary->link_flags = chaz_CC_new_cflags(); + + num_binaries = self->num_binaries; + alloc_size = (num_binaries + 2) * sizeof(chaz_MakeBinary*); + binaries = (chaz_MakeBinary**)realloc(self->binaries, alloc_size); + binaries[num_binaries] = binary; + binaries[num_binaries+1] = NULL; + self->binaries = binaries; + self->num_binaries = num_binaries + 1; + + free(uc_basename); + free(obj_var_name); + free(binary_var_name); + return binary; +} + +chaz_MakeBinary* +chaz_MakeFile_add_lemon_exe(chaz_MakeFile *self, const char *dir) { + chaz_MakeBinary *exe = chaz_MakeFile_add_exe(self, dir, "lemon"); + chaz_MakeBinary_add_src_file(exe, dir, "lemon.c"); - chaz_CFlags_enable_optimization(cflags); - chaz_MakeFile_add_var(makefile, "LEMON_EXE", lemon_exe); - rule = chaz_MakeFile_add_compiled_exe(makefile, "$(LEMON_EXE)", lemon_c, - cflags); + if (chaz_CC_gcc_version_num()) { + chaz_CFlags *cflags = chaz_MakeBinary_get_compile_flags(exe); + chaz_CFlags_append(cflags, "-Wno-pedantic -Wno-sign-compare" + " -Wno-unused-parameter"); + } - chaz_CFlags_destroy(cflags); - free(lemon_c); - free(lemon_exe); - return rule; + return exe; } chaz_MakeRule* -chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *makefile, +chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *self, const char *base_name) { char *c_file = chaz_Util_join(".", base_name, "c", NULL); char *h_file = chaz_Util_join(".", base_name, "h", NULL); char *y_file = chaz_Util_join(".", base_name, "y", NULL); char *command = chaz_Util_join(" ", "$(LEMON_EXE) -q", y_file, NULL); - chaz_MakeRule *rule = chaz_MakeFile_add_rule(makefile, c_file, y_file); - chaz_MakeRule *clean_rule = chaz_MakeFile_clean_rule(makefile); + chaz_MakeRule *rule = chaz_MakeFile_add_rule(self, c_file, y_file); + chaz_MakeRule *clean_rule = chaz_MakeFile_clean_rule(self); chaz_MakeRule_add_prereq(rule, "$(LEMON_EXE)"); chaz_MakeRule_add_command(rule, command); @@ -5030,51 +5078,8 @@ chaz_MakeFile_add_lemon_grammar(chaz_MakeFile *makefile, return rule; } -chaz_MakeRule* -chaz_MakeFile_override_cflags(chaz_MakeFile *makefile, const char *obj, - chaz_CFlags *cflags) { - const char *obj_ext = chaz_CC_obj_ext(); - const char *cflags_string = chaz_CFlags_get_string(cflags); - size_t obj_ext_len = strlen(obj_ext); - size_t obj_len = strlen(obj); - size_t base_len; - char *src; - char *command; - chaz_MakeRule *rule; - - if (obj_len <= obj_ext_len) { - chaz_Util_die("Invalid object file: %s", obj); - } - - base_len = obj_len - obj_ext_len; - - if (strcmp(obj + base_len, obj_ext) != 0) { - chaz_Util_die("Invalid object file: %s", obj); - } - - src = malloc(base_len + sizeof(".c")); - memcpy(src, obj, base_len); - memcpy(src + base_len, ".c", sizeof(".c")); - - rule = chaz_MakeFile_add_rule(makefile, obj, src); - if (chaz_CC_msvc_version_num()) { - command = chaz_Util_join(" ", "$(CC) /nologo", cflags_string, "/c", - src, "/Fo$@", NULL); - } - else { - command = chaz_Util_join(" ", "$(CC)", cflags_string, "-c", src, - "-o $@", NULL); - } - chaz_MakeRule_add_command(rule, command); - - free(command); - free(src); - - return rule; -} - void -chaz_MakeFile_write(chaz_MakeFile *makefile) { +chaz_MakeFile_write(chaz_MakeFile *self) { FILE *out; size_t i; @@ -5083,18 +5088,22 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) { chaz_Util_die("Can't open Makefile\n"); } - for (i = 0; makefile->vars[i]; i++) { - chaz_MakeVar *var = makefile->vars[i]; + for (i = 0; self->vars[i]; i++) { + chaz_MakeVar *var = self->vars[i]; fprintf(out, "%s = %s\n", var->name, var->value); } fprintf(out, "\n"); - for (i = 0; makefile->rules[i]; i++) { - S_write_rule(makefile->rules[i], out); + for (i = 0; self->rules[i]; i++) { + S_chaz_MakeRule_write(self->rules[i], out); } - S_write_rule(makefile->clean, out); - S_write_rule(makefile->distclean, out); + for (i = 0; self->binaries[i]; i++) { + S_chaz_MakeFile_write_binary_rules(self, self->binaries[i], out); + } + + S_chaz_MakeRule_write(self->clean, out); + S_chaz_MakeRule_write(self->distclean, out); /* Suffix rule for .c files. */ if (chaz_CC_msvc_version_num()) { @@ -5109,33 +5118,151 @@ chaz_MakeFile_write(chaz_MakeFile *makefile) { fclose(out); } +static void +S_chaz_MakeFile_write_binary_rules(chaz_MakeFile *self, + chaz_MakeBinary *binary, FILE *out) { + const char *cflags; + + if (chaz_CC_msvc_version_num()) { + chaz_CFlags_append(binary->compile_flags, "/nologo"); + chaz_CFlags_append(binary->link_flags, "/nologo"); + } + + switch (binary->type) { + case CHAZ_MAKEBINARY_EXE: + S_chaz_MakeFile_finish_exe(self, binary); + break; + case CHAZ_MAKEBINARY_STATIC_LIB: + S_chaz_MakeFile_finish_static_lib(self, binary); + break; + case CHAZ_MAKEBINARY_SHARED_LIB: + S_chaz_MakeFile_finish_shared_lib(self, binary); + break; + default: + chaz_Util_die("Invalid binary type: %d", binary->type); + return; + } + + chaz_MakeRule_add_rm_command(self->clean, binary->rule->targets); + chaz_MakeRule_add_rm_command(self->clean, binary->dollar_var); + + S_chaz_MakeRule_write(binary->rule, out); + + cflags = chaz_CFlags_get_string(binary->compile_flags); + + /* Write rules to compile with custom flags. */ + if (cflags[0] != '\0') { + if (chaz_Make.shell_type == CHAZ_OS_CMD_EXE) { + /* Write a rule for each object file. This is needed for nmake + * which doesn't support pattern rules but also for mingw32-make + * which has problems with pattern rules and backslash directory + * separators. + */ + S_chaz_MakeFile_write_object_rules(binary->sources, cflags, out); + } + else { + /* Write a pattern rule for each directory. */ + S_chaz_MakeFile_write_pattern_rules(binary->dirs, cflags, out); + /* Write a rule for each object added with add_src_file. */ + S_chaz_MakeFile_write_object_rules(binary->single_sources, cflags, + out); + } + } +} + +static void +S_chaz_MakeFile_write_object_rules(char **sources, const char *cflags, + FILE *out) { + chaz_CFlags *output_cflags = chaz_CC_new_cflags(); + const char *output_cflags_string; + size_t i; + + chaz_CFlags_set_output_obj(output_cflags, "$@"); + output_cflags_string = chaz_CFlags_get_string(output_cflags); + + for (i = 0; sources[i]; i++) { + const char *source = sources[i]; + char *obj_path = S_chaz_MakeBinary_obj_path(source); + chaz_MakeRule *rule; + char *command; + + if (obj_path == NULL) { continue; } + + rule = S_chaz_MakeRule_new(obj_path, source); + command = chaz_Util_join(" ", "$(CC) $(CFLAGS)", cflags, source, + output_cflags_string, NULL); + chaz_MakeRule_add_command(rule, command); + S_chaz_MakeRule_write(rule, out); + + free(command); + S_chaz_MakeRule_destroy(rule); + free(obj_path); + } + + chaz_CFlags_destroy(output_cflags); +} + +static void +S_chaz_MakeFile_write_pattern_rules(char **dirs, const char *cflags, + FILE *out) { + const char *obj_ext = chaz_CC_obj_ext(); + const char *dir_sep = chaz_OS_dir_sep(); + chaz_CFlags *output_cflags = chaz_CC_new_cflags(); + const char *output_cflags_string; + char *command; + size_t i; + + chaz_CFlags_set_output_obj(output_cflags, "$@"); + output_cflags_string = chaz_CFlags_get_string(output_cflags); + command = chaz_Util_join(" ", "$(CC) $(CFLAGS)", cflags, "$<", + output_cflags_string, NULL); + + for (i = 0; dirs[i]; i++) { + const char *dir = dirs[i]; + char *target = chaz_Util_join("", dir, dir_sep, "%", obj_ext, + NULL); + char *prereq = chaz_Util_join("", dir, dir_sep, "%.c", NULL); + chaz_MakeRule *rule = S_chaz_MakeRule_new(target, prereq); + + chaz_MakeRule_add_command(rule, command); + S_chaz_MakeRule_write(rule, out); + + S_chaz_MakeRule_destroy(rule); + free(prereq); + free(target); + } + + free(command); + chaz_CFlags_destroy(output_cflags); +} + void -chaz_MakeVar_append(chaz_MakeVar *var, const char *element) { +chaz_MakeVar_append(chaz_MakeVar *self, const char *element) { char *value; if (element[0] == '\0') { return; } - if (var->num_elements == 0) { + if (self->num_elements == 0) { value = chaz_Util_strdup(element); } else { - value = (char*)malloc(strlen(var->value) + strlen(element) + 20); + value = (char*)malloc(strlen(self->value) + strlen(element) + 20); - if (var->num_elements == 1) { - sprintf(value, "\\\n %s \\\n %s", var->value, element); + if (self->num_elements == 1) { + sprintf(value, "\\\n %s \\\n %s", self->value, element); } else { - sprintf(value, "%s \\\n %s", var->value, element); + sprintf(value, "%s \\\n %s", self->value, element); } } - free(var->value); - var->value = value; - var->num_elements++; + free(self->value); + self->value = value; + self->num_elements++; } static chaz_MakeRule* -S_new_rule(const char *target, const char *prereq) { +S_chaz_MakeRule_new(const char *target, const char *prereq) { chaz_MakeRule *rule = (chaz_MakeRule*)malloc(sizeof(chaz_MakeRule)); rule->targets = NULL; @@ -5149,75 +5276,75 @@ S_new_rule(const char *target, const char *prereq) { } static void -S_destroy_rule(chaz_MakeRule *rule) { - if (rule->targets) { free(rule->targets); } - if (rule->prereqs) { free(rule->prereqs); } - if (rule->commands) { free(rule->commands); } - free(rule); +S_chaz_MakeRule_destroy(chaz_MakeRule *self) { + if (self->targets) { free(self->targets); } + if (self->prereqs) { free(self->prereqs); } + if (self->commands) { free(self->commands); } + free(self); } static void -S_write_rule(chaz_MakeRule *rule, FILE *out) { - fprintf(out, "%s :", rule->targets); - if (rule->prereqs) { - fprintf(out, " %s", rule->prereqs); +S_chaz_MakeRule_write(chaz_MakeRule *self, FILE *out) { + fprintf(out, "%s :", self->targets); + if (self->prereqs) { + fprintf(out, " %s", self->prereqs); } fprintf(out, "\n"); - if (rule->commands) { - fprintf(out, "%s", rule->commands); + if (self->commands) { + fprintf(out, "%s", self->commands); } fprintf(out, "\n"); } void -chaz_MakeRule_add_target(chaz_MakeRule *rule, const char *target) { +chaz_MakeRule_add_target(chaz_MakeRule *self, const char *target) { char *targets; - if (!rule->targets) { + if (!self->targets) { targets = chaz_Util_strdup(target); } else { - targets = chaz_Util_join(" ", rule->targets, target, NULL); - free(rule->targets); + targets = chaz_Util_join(" ", self->targets, target, NULL); + free(self->targets); } - rule->targets = targets; + self->targets = targets; } void -chaz_MakeRule_add_prereq(chaz_MakeRule *rule, const char *prereq) { +chaz_MakeRule_add_prereq(chaz_MakeRule *self, const char *prereq) { char *prereqs; - if (!rule->prereqs) { + if (!self->prereqs) { prereqs = chaz_Util_strdup(prereq); } else { - prereqs = chaz_Util_join(" ", rule->prereqs, prereq, NULL); - free(rule->prereqs); + prereqs = chaz_Util_join(" ", self->prereqs, prereq, NULL); + free(self->prereqs); } - rule->prereqs = prereqs; + self->prereqs = prereqs; } void -chaz_MakeRule_add_command(chaz_MakeRule *rule, const char *command) { +chaz_MakeRule_add_command(chaz_MakeRule *self, const char *command) { char *commands; - if (!rule->commands) { + if (!self->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); + commands = (char*)malloc(strlen(self->commands) + strlen(command) + 20); + sprintf(commands, "%s\t%s\n", self->commands, command); + free(self->commands); } - rule->commands = commands; + self->commands = commands; } void -chaz_MakeRule_add_command_with_libpath(chaz_MakeRule *rule, +chaz_MakeRule_add_command_with_libpath(chaz_MakeRule *self, const char *command, ...) { va_list args; char *path = NULL; @@ -5264,12 +5391,12 @@ chaz_MakeRule_add_command_with_libpath(chaz_MakeRule *rule, lib_command = chaz_Util_strdup(command); } - chaz_MakeRule_add_command(rule, lib_command); + chaz_MakeRule_add_command(self, lib_command); free(lib_command); } void -chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files) { +chaz_MakeRule_add_rm_command(chaz_MakeRule *self, const char *files) { char *command; if (chaz_Make.shell_type == CHAZ_OS_POSIX) { @@ -5283,12 +5410,12 @@ chaz_MakeRule_add_rm_command(chaz_MakeRule *rule, const char *files) { chaz_Util_die("Unsupported shell type: %d", chaz_Make.shell_type); } - chaz_MakeRule_add_command(rule, command); + chaz_MakeRule_add_command(self, command); free(command); } void -chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs) { +chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *self, const char *dirs) { char *command; if (chaz_Make.shell_type == CHAZ_OS_POSIX) { @@ -5302,12 +5429,12 @@ chaz_MakeRule_add_recursive_rm_command(chaz_MakeRule *rule, const char *dirs) { chaz_Util_die("Unsupported shell type: %d", chaz_Make.shell_type); } - chaz_MakeRule_add_command(rule, command); + chaz_MakeRule_add_command(self, command); free(command); } void -chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir, +chaz_MakeRule_add_make_command(chaz_MakeRule *self, const char *dir, const char *target) { char *command; @@ -5319,7 +5446,7 @@ chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir, command = chaz_Util_join("", "(cd ", dir, " && $(MAKE) ", target, ")", NULL); } - chaz_MakeRule_add_command(rule, command); + chaz_MakeRule_add_command(self, command); free(command); } else if (chaz_Make.shell_type == CHAZ_OS_CMD_EXE) { @@ -5331,7 +5458,7 @@ chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir, command = chaz_Util_join(" ", "pushd", dir, "&& $(MAKE)", target, "&& popd", NULL); } - chaz_MakeRule_add_command(rule, command); + chaz_MakeRule_add_command(self, command); free(command); } else { @@ -5339,6 +5466,170 @@ chaz_MakeRule_add_make_command(chaz_MakeRule *rule, const char *dir, } } +static void +S_chaz_MakeBinary_destroy(chaz_MakeBinary *self) { + size_t i; + + free(self->target_dir); + free(self->basename); + free(self->version); + free(self->major_version); + free(self->dollar_var); + S_chaz_MakeRule_destroy(self->rule); + + for (i = 0; i < self->num_sources; i++) { + free(self->sources[i]); + } + free(self->sources); + for (i = 0; i < self->num_single_sources; i++) { + free(self->single_sources[i]); + } + free(self->single_sources); + for (i = 0; i < self->num_dirs; i++) { + free(self->dirs[i]); + } + free(self->dirs); + + chaz_CFlags_destroy(self->compile_flags); + chaz_CFlags_destroy(self->link_flags); + + free(self); +} + +void +chaz_MakeBinary_add_src_file(chaz_MakeBinary *self, const char *dir, + const char *filename) { + size_t num_sources = self->num_single_sources; + size_t alloc_size = (num_sources + 2) * sizeof(char*); + char **sources = (char**)realloc(self->single_sources, alloc_size); + char *path; + + if (dir == NULL || strcmp(dir, ".") == 0) { + path = chaz_Util_strdup(filename); + } + else { + const char *dir_sep = chaz_OS_dir_sep(); + path = chaz_Util_join(dir_sep, dir, filename, NULL); + } + + /* Add to single_sources. */ + sources[num_sources] = path; + sources[num_sources+1] = NULL; + self->single_sources = sources; + self->num_single_sources = num_sources + 1; + + S_chaz_MakeBinary_do_add_src_file(self, path); +} + +void +chaz_MakeBinary_add_src_dir(chaz_MakeBinary *self, const char *path) { + size_t num_dirs = self->num_dirs; + char **dirs = (char**)realloc(self->dirs, (num_dirs + 2) * sizeof(char*)); + + dirs[num_dirs] = chaz_Util_strdup(path); + dirs[num_dirs+1] = NULL; + self->dirs = dirs; + self->num_dirs = num_dirs + 1; + + chaz_Make_list_files(path, "c", S_chaz_MakeBinary_list_files_callback, + self); +} + +static void +S_chaz_MakeBinary_list_files_callback(const char *dir, char *file, + void *context) { + const char *dir_sep = chaz_OS_dir_sep(); + char *path = chaz_Util_join(dir_sep, dir, file, NULL); + + S_chaz_MakeBinary_do_add_src_file((chaz_MakeBinary*)context, path); + free(path); +} + +static void +S_chaz_MakeBinary_do_add_src_file(chaz_MakeBinary *self, const char *path) { + size_t num_sources = self->num_sources; + size_t alloc_size = (num_sources + 2) * sizeof(char*); + char **sources = (char**)realloc(self->sources, alloc_size); + char *obj_path; + + sources[num_sources] = chaz_Util_strdup(path); + sources[num_sources+1] = NULL; + self->sources = sources; + self->num_sources = num_sources + 1; + + obj_path = S_chaz_MakeBinary_obj_path(path); + if (obj_path == NULL) { + chaz_Util_warn("Invalid source filename: %s", path); + } + else { + chaz_MakeVar_append(self->obj_var, obj_path); + free(obj_path); + } +} + +static char* +S_chaz_MakeBinary_obj_path(const char *src_path) { + const char *dir_sep = chaz_OS_dir_sep(); + const char *obj_ext = chaz_CC_obj_ext(); + size_t obj_ext_len = strlen(obj_ext); + size_t i = strlen(src_path); + char *retval; + + while (i > 0) { + i -= 1; + if (src_path[i] == dir_sep[0]) { return NULL; } + if (src_path[i] == '.') { break; } + } + + if (src_path[i] != '.') { return NULL; } + + retval = (char*)malloc(i + obj_ext_len + 1); + memcpy(retval, src_path, i); + memcpy(retval + i, obj_ext, obj_ext_len + 1); + + return retval; +} + +void +chaz_MakeBinary_add_prereq(chaz_MakeBinary *self, const char *prereq) { + chaz_MakeRule_add_prereq(self->rule, prereq); +} + +char* +chaz_MakeBinary_obj_string(chaz_MakeBinary *self) { + char *retval = chaz_Util_strdup(""); + size_t i; + + for (i = 0; i < self->num_sources; i++) { + const char *sep = retval[0] == '\0' ? "" : " "; + char *obj_path = S_chaz_MakeBinary_obj_path(self->sources[i]); + char *tmp; + + if (obj_path == NULL) { continue; } + + tmp = chaz_Util_join("", retval, sep, obj_path, NULL); + free(retval); + retval = tmp; + } + + return retval; +} + +const char* +chaz_MakeBinary_get_target(chaz_MakeBinary *self) { + return self->rule->targets; +} + +chaz_CFlags* +chaz_MakeBinary_get_compile_flags(chaz_MakeBinary *self) { + return self->compile_flags; +} + +chaz_CFlags* +chaz_MakeBinary_get_link_flags(chaz_MakeBinary *self) { + return self->link_flags; +} + void chaz_Make_list_files(const char *dir, const char *ext, chaz_Make_list_files_callback_t callback, void *context) { @@ -6531,7 +6822,7 @@ chaz_Floats_math_library(void) { return NULL; } - chaz_CFlags_add_external_library(temp_cflags, "m"); + chaz_CFlags_add_external_lib(temp_cflags, "m"); output = chaz_CC_capture_output(sqrt_code, &output_len); chaz_CFlags_clear(temp_cflags); @@ -7483,6 +7774,12 @@ chaz_Integers_run(void) { chaz_ConfWriter_start_module("IntegerFormatStrings"); if (has_inttypes) { + if (chaz_CC_is_mingw()) { + /* Suppress warnings about undefined inline function `llabs` + * under MinGW. + */ + chaz_ConfWriter_add_sys_include("stdlib.h"); + } chaz_ConfWriter_add_sys_include("inttypes.h"); } @@ -8307,9 +8604,8 @@ chaz_VariadicMacros_run(void) { /* #include "Charmonizer/Probe/Integers.h" */ typedef struct SourceFileContext { - chaz_MakeVar *common_objs; - chaz_MakeVar *test_cfc_objs; - chaz_MakeVar *common_test_objs; + chaz_MakeBinary *core_binary; + chaz_MakeBinary *test_binary; } SourceFileContext; static const char cfc_version[] = "0.5.0"; @@ -8414,42 +8710,30 @@ S_add_compiler_flags(struct chaz_CLI *cli) { } static void -S_add_staticlib_makefile_target(chaz_MakeFile *makefile) { - chaz_Lib *static_lib = chaz_Lib_new_static("cfc"); - char *static_lib_filename = chaz_Lib_filename(static_lib); - chaz_MakeFile_add_rule(makefile, "static", static_lib_filename); - chaz_MakeFile_add_static_lib(makefile, static_lib, "$(COMMON_OBJS)"); - free(static_lib_filename); - chaz_Lib_destroy(static_lib); -} - -static void S_write_makefile(struct chaz_CLI *cli) { SourceFileContext sfc; const char *base_dir = ".."; const char *dir_sep = chaz_OS_dir_sep(); - const char *exe_ext = chaz_CC_exe_ext(); - const char *obj_ext = chaz_CC_obj_ext(); - - char *lemon_dir = chaz_Util_join(dir_sep, base_dir, "..", "lemon", - NULL); - char *src_dir = chaz_Util_join(dir_sep, base_dir, "src", NULL); - char *include_dir = chaz_Util_join(dir_sep, base_dir, "include", NULL); - char *cmark_dir = chaz_Util_join(dir_sep, base_dir, "modules", - "CommonMark", "src", NULL); - char *parse_header = chaz_Util_join(dir_sep, src_dir, "CFCParseHeader", - NULL); - char *cfc_exe = chaz_Util_join("", "cfc", exe_ext, NULL); - char *test_cfc_exe = chaz_Util_join("", "t", dir_sep, "test_cfc", exe_ext, - NULL); - - char *scratch; - - chaz_MakeFile *makefile; - chaz_MakeVar *var; - chaz_MakeRule *rule; - chaz_MakeRule *clean_rule; + const char *host = chaz_CLI_strval(cli, "host"); + + char *lemon_dir = chaz_Util_join(dir_sep, base_dir, "..", "lemon", + NULL); + char *src_dir = chaz_Util_join(dir_sep, base_dir, "src", NULL); + char *include_dir = chaz_Util_join(dir_sep, base_dir, "include", NULL); + char *cmark_dir = chaz_Util_join(dir_sep, base_dir, "modules", + "CommonMark", "src", NULL); + char *parse_header = chaz_Util_join(dir_sep, src_dir, "CFCParseHeader", + NULL); + char *parse_header_c = chaz_Util_join(dir_sep, src_dir, "CFCParseHeader.c", + NULL); + + chaz_MakeFile *makefile = NULL; + chaz_MakeBinary *lib = NULL; + chaz_MakeBinary *exe = NULL; + chaz_MakeBinary *test_exe = NULL; + chaz_MakeVar *var = NULL; + chaz_MakeRule *rule = NULL; chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags(); chaz_CFlags *makefile_cflags; @@ -8486,107 +8770,89 @@ S_write_makefile(struct chaz_CLI *cli) { chaz_CFlags_destroy(makefile_cflags); - /* Object files */ - - sfc.common_objs = chaz_MakeFile_add_var(makefile, "COMMON_OBJS", NULL); - sfc.test_cfc_objs = chaz_MakeFile_add_var(makefile, "TEST_CFC_OBJS", NULL); - sfc.common_test_objs = chaz_MakeFile_add_var(makefile, "COMMON_TEST_OBJS", NULL); + /* Binaries. */ - chaz_Make_list_files(src_dir, "c", S_source_file_callback, &sfc); - chaz_Make_list_files(cmark_dir, "c", S_source_file_callback, &sfc); - - scratch = chaz_Util_join("", parse_header, obj_ext, NULL); - chaz_MakeVar_append(sfc.common_objs, scratch); - free(scratch); + if (strcmp(host, "c") == 0) { + chaz_CFlags *link_flags; - scratch = chaz_Util_join("", "t", dir_sep, "test_cfc", obj_ext, NULL); - chaz_MakeVar_append(sfc.test_cfc_objs, scratch); - free(scratch); + chaz_MakeFile_add_rule(makefile, "all", "$(CFC_EXE)"); - scratch = chaz_Util_join("", "cfc", obj_ext, NULL); - chaz_MakeFile_add_var(makefile, "CFC_OBJS", scratch); - free(scratch); - - /* Rules */ + exe = chaz_MakeFile_add_exe(makefile, NULL, "cfc"); + chaz_MakeBinary_add_src_file(exe, NULL, "cfc.c"); + chaz_MakeBinary_add_prereq(exe, "$(CFC_STATIC_LIB)"); + link_flags = chaz_MakeBinary_get_link_flags(exe); + chaz_CFlags_append(link_flags, "$(CFC_STATIC_LIB)"); - chaz_MakeFile_add_rule(makefile, "all", cfc_exe); - S_add_staticlib_makefile_target(makefile); + test_exe = chaz_MakeFile_add_exe(makefile, "t", "test_cfc"); + chaz_MakeBinary_add_src_file(test_exe, "t", "test_cfc.c"); + chaz_MakeBinary_add_prereq(test_exe, "$(CFC_STATIC_LIB)"); + link_flags = chaz_MakeBinary_get_link_flags(test_exe); + chaz_CFlags_append(link_flags, "$(CFC_STATIC_LIB)"); + } - chaz_MakeFile_add_lemon_exe(makefile, lemon_dir); - chaz_MakeFile_add_lemon_grammar(makefile, parse_header); + lib = chaz_MakeFile_add_static_lib(makefile, NULL, "cfc"); + chaz_MakeFile_add_rule(makefile, "static", "$(CFC_STATIC_LIB)"); /* * The dependency is actually on CFCParseHeader.h, but make doesn't cope * well with multiple output files. */ - scratch = chaz_Util_join(".", parse_header, "c", NULL); - chaz_MakeFile_add_rule(makefile, "$(COMMON_OBJS)", scratch); - free(scratch); - - link_flags = chaz_CC_new_cflags(); - if (chaz_CC_msvc_version_num()) { - chaz_CFlags_append(link_flags, "/nologo"); - } - if (chaz_CLI_defined(cli, "enable-coverage")) { - chaz_CFlags_enable_code_coverage(link_flags); - } - if (strcmp(chaz_CLI_strval(cli, "host"), "c") == 0) { - chaz_MakeFile_add_exe(makefile, cfc_exe, "$(COMMON_OBJS) $(CFC_OBJS)", - link_flags); - chaz_MakeFile_add_exe(makefile, test_cfc_exe, - "$(COMMON_OBJS) $(COMMON_TEST_OBJS) $(TEST_CFC_OBJS)", - link_flags); - } - chaz_CFlags_destroy(link_flags); + chaz_MakeFile_add_rule(makefile, "$(CFC_STATIC_LIB_OBJS)", parse_header_c); - rule = chaz_MakeFile_add_rule(makefile, "test", "all"); - chaz_MakeRule_add_prereq(rule, test_cfc_exe); - chaz_MakeRule_add_command(rule, test_cfc_exe); + sfc.core_binary = lib; + sfc.test_binary = test_exe; + chaz_Make_list_files(src_dir, "c", S_source_file_callback, &sfc); + chaz_Make_list_files(cmark_dir, "c", S_source_file_callback, &sfc); - if (chaz_OS_shell_type() == CHAZ_OS_POSIX) { - rule = chaz_MakeFile_add_rule(makefile, "valgrind", "all"); - chaz_MakeRule_add_prereq(rule, test_cfc_exe); - scratch = chaz_Util_join(" ", "CLOWNFISH_VALGRIND=1", "valgrind", - "--leak-check=full", test_cfc_exe, NULL); - chaz_MakeRule_add_command(rule, scratch); - free(scratch); - } + chaz_MakeBinary_add_src_file(lib, src_dir, "CFCParseHeader.c"); - if (chaz_CLI_defined(cli, "enable-coverage")) { - rule = chaz_MakeFile_add_rule(makefile, "coverage", test_cfc_exe); - chaz_MakeRule_add_command(rule, - "lcov" - " --zerocounters" - " --directory $(BASE_DIR)"); - chaz_MakeRule_add_command(rule, test_cfc_exe); - chaz_MakeRule_add_command(rule, - "lcov" - " --capture" - " --directory $(BASE_DIR)" - " --base-directory ." - " --rc lcov_branch_coverage=1" - " --output-file cfc.info"); - chaz_MakeRule_add_command(rule, - "genhtml" - " --branch-coverage" - " --output-directory coverage" - " cfc.info"); - } - - clean_rule = chaz_MakeFile_clean_rule(makefile); - - chaz_MakeRule_add_rm_command(clean_rule, "$(COMMON_OBJS)"); - chaz_MakeRule_add_rm_command(clean_rule, "$(COMMON_TEST_OBJS)"); - chaz_MakeRule_add_rm_command(clean_rule, "$(CFC_OBJS)"); - chaz_MakeRule_add_rm_command(clean_rule, "$(TEST_CFC_OBJS)"); + /* Rules */ - if (chaz_CLI_defined(cli, "enable-coverage")) { - chaz_MakeRule_add_rm_command(clean_rule, "cfc.info"); - chaz_MakeRule_add_recursive_rm_command(clean_rule, "coverage"); - } + chaz_MakeFile_add_lemon_exe(makefile, lemon_dir); + chaz_MakeFile_add_lemon_grammar(makefile, parse_header); - if (chaz_Probe_msvc_version_num()) { - chaz_MakeRule_add_rm_command(clean_rule, "lemon.obj"); + if (strcmp(host, "c") == 0) { + rule = chaz_MakeFile_add_rule(makefile, "test", "all"); + chaz_MakeRule_add_prereq(rule, "$(TEST_CFC_EXE)"); + chaz_MakeRule_add_command(rule, "$(TEST_CFC_EXE)"); + + if (chaz_OS_shell_type() == CHAZ_OS_POSIX) { + rule = chaz_MakeFile_add_rule(makefile, "valgrind", "all"); + chaz_MakeRule_add_prereq(rule, "$(TEST_CFC_EXE)"); + chaz_MakeRule_add_command(rule, + "CLOWNFISH_VALGRIND=1 valgrind" + " --leak-check=full" + " $(TEST_CFC_EXE)"); + } + + if (chaz_CLI_defined(cli, "enable-coverage")) { + link_flags = chaz_MakeBinary_get_link_flags(test_exe); + chaz_CFlags_enable_code_coverage(link_flags); + + rule = chaz_MakeFile_add_rule(makefile, "coverage", + "$(TEST_CFC_EXE)"); + chaz_MakeRule_add_command(rule, + "lcov" + " --zerocounters" + " --directory $(BASE_DIR)"); + chaz_MakeRule_add_command(rule, "$(TEST_CFC_EXE)"); + chaz_MakeRule_add_command(rule, + "lcov" + " --capture"
<TRUNCATED>