| /* Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* Source fragment for the Clownfish runtime's charmonizer.c. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include "Charmonizer/Probe.h" |
| #include "Charmonizer/Probe/AtomicOps.h" |
| #include "Charmonizer/Probe/BuildEnv.h" |
| #include "Charmonizer/Probe/DirManip.h" |
| #include "Charmonizer/Probe/Floats.h" |
| #include "Charmonizer/Probe/FuncMacro.h" |
| #include "Charmonizer/Probe/Headers.h" |
| #include "Charmonizer/Probe/Integers.h" |
| #include "Charmonizer/Probe/LargeFiles.h" |
| #include "Charmonizer/Probe/Memory.h" |
| #include "Charmonizer/Probe/SymbolVisibility.h" |
| #include "Charmonizer/Probe/VariadicMacros.h" |
| #include "Charmonizer/Core/HeaderChecker.h" |
| #include "Charmonizer/Core/CLI.h" |
| #include "Charmonizer/Core/ConfWriter.h" |
| #include "Charmonizer/Core/ConfWriterC.h" |
| #include "Charmonizer/Core/ConfWriterPerl.h" |
| #include "Charmonizer/Core/ConfWriterRuby.h" |
| |
| typedef struct cfish_MakeFile { |
| chaz_MakeFile *makefile; |
| chaz_MakeBinary *lib; |
| chaz_MakeBinary *test_lib; |
| chaz_MakeVar *cfh_var; |
| chaz_CLI *cli; |
| |
| /* Directories and files. */ |
| const char *base_dir; |
| const char *host_src_dir; |
| char *core_dir; |
| char *test_dir; |
| char *autogen_src_dir; |
| char *autogen_inc_dir; |
| char *autogen_target; |
| } cfish_MakeFile; |
| |
| static const char cfish_version[] = "0.6.0"; |
| static const char cfish_major_version[] = "0.6"; |
| |
| static void |
| S_add_compiler_flags(struct chaz_CLI *cli); |
| |
| static chaz_CFlags* |
| S_link_flags(chaz_CLI *cli); |
| |
| static cfish_MakeFile* |
| cfish_MakeFile_new(chaz_CLI *cli); |
| |
| static void |
| cfish_MakeFile_destroy(cfish_MakeFile *self); |
| |
| static void |
| cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags); |
| |
| static void |
| cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self); |
| |
| static void |
| cfish_MakeFile_write_c_test_rules(cfish_MakeFile *self); |
| |
| static void |
| cfish_MakeFile_write_c_install_rules(cfish_MakeFile *self); |
| |
| static void |
| S_cfh_file_callback(const char *dir, char *file, void *context); |
| |
| static int |
| S_ends_with(const char *string, const char *postfix); |
| |
| static int |
| S_need_libpthread(chaz_CLI *cli); |
| |
| int main(int argc, const char **argv) { |
| chaz_CFlags *link_flags; |
| |
| /* Initialize. */ |
| chaz_CLI *cli |
| = chaz_CLI_new(argv[0], "charmonizer: Probe C build environment"); |
| chaz_CLI_register(cli, "host", "specify host binding language", |
| CHAZ_CLI_ARG_REQUIRED); |
| chaz_CLI_register(cli, "disable-threads", "whether to disable threads", |
| CHAZ_CLI_NO_ARG); |
| chaz_CLI_set_usage(cli, "Usage: charmonizer [OPTIONS] [-- [CFLAGS]]"); |
| if (!chaz_Probe_parse_cli_args(argc, argv, cli)) { |
| chaz_Probe_die_usage(); |
| } |
| if (!chaz_CLI_defined(cli, "host")) { |
| chaz_CLI_set(cli, "host", "c"); |
| } |
| chaz_Probe_init(cli); |
| S_add_compiler_flags(cli); |
| |
| /* Employ integer features but don't define stdint types in charmony.h. */ |
| chaz_ConfWriter_append_conf( |
| "#define CHY_EMPLOY_INTEGERLIMITS\n" |
| "#define CHY_EMPLOY_INTEGERLITERALS\n" |
| "#define CHY_EMPLOY_INTEGERFORMATSTRINGS\n\n" |
| ); |
| |
| /* Run probe modules. Booleans, DirManip and LargeFiles are only needed for |
| * the Charmonizer tests. |
| */ |
| chaz_BuildEnv_run(); |
| chaz_DirManip_run(); |
| chaz_Headers_run(); |
| chaz_AtomicOps_run(); |
| chaz_FuncMacro_run(); |
| chaz_Booleans_run(); |
| chaz_Integers_run(); |
| chaz_Floats_run(); |
| chaz_LargeFiles_run(); |
| chaz_Memory_run(); |
| chaz_SymbolVisibility_run(); |
| chaz_VariadicMacros_run(); |
| |
| /* Local definitions. */ |
| chaz_ConfWriter_start_module("LocalDefinitions"); |
| if (chaz_HeadCheck_defines_symbol("__sync_bool_compare_and_swap", "")) { |
| chaz_ConfWriter_add_def("HAS___SYNC_BOOL_COMPARE_AND_SWAP", NULL); |
| } |
| link_flags = S_link_flags(cli); |
| chaz_ConfWriter_add_def("EXTRA_LDFLAGS", |
| chaz_CFlags_get_string(link_flags)); |
| chaz_ConfWriter_end_module(); |
| |
| /* Write custom postamble. */ |
| chaz_ConfWriter_append_conf( |
| "#ifdef CHY_HAS_SYS_TYPES_H\n" |
| " #include <sys/types.h>\n" |
| "#endif\n\n" |
| ); |
| chaz_ConfWriter_append_conf( |
| "#ifdef CHY_HAS_ALLOCA_H\n" |
| " #include <alloca.h>\n" |
| "#elif defined(CHY_HAS_MALLOC_H)\n" |
| " #include <malloc.h>\n" |
| "#elif defined(CHY_ALLOCA_IN_STDLIB_H)\n" |
| " #include <stdlib.h>\n" |
| "#endif\n\n" |
| ); |
| chaz_ConfWriter_append_conf( |
| "#ifdef CHY_HAS_WINDOWS_H\n" |
| " /* Target Windows XP. */\n" |
| " #ifndef WINVER\n" |
| " #define WINVER 0x0500\n" |
| " #endif\n" |
| " #ifndef _WIN32_WINNT\n" |
| " #define _WIN32_WINNT 0x0500\n" |
| " #endif\n" |
| "#endif\n\n" |
| ); |
| |
| if (chaz_CLI_defined(cli, "enable-makefile")) { |
| cfish_MakeFile *mf = cfish_MakeFile_new(cli); |
| cfish_MakeFile_write(mf, link_flags); |
| cfish_MakeFile_destroy(mf); |
| } |
| |
| /* Clean up. */ |
| chaz_CFlags_destroy(link_flags); |
| chaz_CLI_destroy(cli); |
| chaz_Probe_clean_up(); |
| |
| return 0; |
| } |
| |
| static void |
| S_add_compiler_flags(struct chaz_CLI *cli) { |
| chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags(); |
| |
| if (chaz_CC_is_gcc()) { |
| if (!chaz_CC_is_mingw()) { |
| /* When using the MSVCRT, -pedantic complains about %I64 format |
| * specifiers. |
| */ |
| chaz_CFlags_append(extra_cflags, "-pedantic"); |
| } |
| chaz_CFlags_append(extra_cflags, "-Wall -Wextra -Wno-variadic-macros"); |
| if (strcmp(chaz_CLI_strval(cli, "host"), "perl") == 0) { |
| chaz_CFlags_append(extra_cflags, "-DPERL_GCC_PEDANTIC"); |
| } |
| |
| /* Only core source files require this -- not our headers and |
| * autogenerated files. */ |
| chaz_CFlags_append(extra_cflags, "-std=gnu99 -D_GNU_SOURCE"); |
| |
| if (chaz_CLI_defined(cli, "enable-coverage")) { |
| /* Some code paths in the float/int comparison code aren't |
| * triggered if excess precision is allowed. */ |
| chaz_CFlags_append(extra_cflags, "-ffloat-store"); |
| } |
| } |
| else if (chaz_CC_is_msvc()) { |
| if (chaz_CC_test_msvc_version("< 1800")) { |
| /* Compile as C++ under MSVC11 and below. */ |
| chaz_CFlags_append(extra_cflags, "/TP"); |
| } |
| |
| chaz_CFlags_append(extra_cflags, "/W3"); |
| /* Thwart stupid warnings. */ |
| chaz_CFlags_append(extra_cflags, "/D_CRT_SECURE_NO_WARNINGS"); |
| chaz_CFlags_append(extra_cflags, "/D_SCL_SECURE_NO_WARNINGS"); |
| } |
| |
| chaz_CFlags_hide_symbols(extra_cflags); |
| |
| if (chaz_CLI_defined(cli, "disable-threads")) { |
| chaz_CFlags_append(extra_cflags, "-DCFISH_NOTHREADS"); |
| } |
| } |
| |
| static chaz_CFlags* |
| S_link_flags(chaz_CLI *cli) { |
| chaz_CFlags *link_flags = chaz_CC_new_cflags(); |
| const char *math_library = chaz_Floats_math_library(); |
| |
| if (math_library) { |
| chaz_CFlags_add_external_lib(link_flags, math_library); |
| } |
| if (S_need_libpthread(cli)) { |
| chaz_CFlags_add_external_lib(link_flags, "pthread"); |
| } |
| if (chaz_CLI_defined(cli, "enable-coverage")) { |
| chaz_CFlags_enable_code_coverage(link_flags); |
| } |
| |
| return link_flags; |
| } |
| |
| static cfish_MakeFile* |
| cfish_MakeFile_new(chaz_CLI *cli) { |
| const char *dir_sep = chaz_OS_dir_sep(); |
| char *cfcore_filename = chaz_Util_join(dir_sep, "cfcore", "Clownfish.cfp", |
| NULL); |
| cfish_MakeFile *self = malloc(sizeof(cfish_MakeFile)); |
| |
| self->makefile = chaz_MakeFile_new(); |
| self->lib = NULL; |
| self->test_lib = NULL; |
| self->cfh_var = NULL; |
| self->cli = cli; |
| |
| if (chaz_Util_can_open_file(cfcore_filename)) { |
| self->base_dir = "."; |
| self->core_dir = chaz_Util_strdup("cfcore"); |
| self->test_dir = chaz_Util_strdup("cftest"); |
| } |
| else { |
| self->base_dir = ".."; |
| self->core_dir = chaz_Util_join(dir_sep, "..", "core", NULL); |
| self->test_dir = chaz_Util_join(dir_sep, "..", "test", NULL); |
| } |
| |
| self->autogen_src_dir = chaz_Util_join(dir_sep, "autogen", "source", NULL); |
| self->autogen_inc_dir |
| = chaz_Util_join(dir_sep, "autogen", "include", NULL); |
| self->autogen_target |
| = chaz_Util_join(dir_sep, "autogen", "hierarchy.json", NULL); |
| |
| if (strcmp(chaz_CLI_strval(cli, "host"), "go") == 0) { |
| /* TODO: Let Go bindings build code in "ext". */ |
| self->host_src_dir = "ext"; |
| } |
| else if (chaz_CLI_defined(cli, "enable-python")) { |
| /* TODO: Let Python bindings build code in "cfext". */ |
| self->host_src_dir = "cfext"; |
| } |
| else if (strcmp(chaz_CLI_strval(cli, "host"), "c") == 0) { |
| self->host_src_dir = "src"; |
| } |
| else { |
| self->host_src_dir = NULL; |
| } |
| |
| free(cfcore_filename); |
| return self; |
| } |
| |
| static void |
| cfish_MakeFile_destroy(cfish_MakeFile *self) { |
| chaz_MakeFile_destroy(self->makefile); |
| |
| free(self->core_dir); |
| free(self->test_dir); |
| free(self->autogen_inc_dir); |
| free(self->autogen_src_dir); |
| free(self->autogen_target); |
| |
| free(self); |
| } |
| |
| static void |
| cfish_MakeFile_write(cfish_MakeFile *self, chaz_CFlags *extra_link_flags) { |
| const char *host = chaz_CLI_strval(self->cli, "host"); |
| int is_c = strcmp(host, "c") == 0; |
| |
| const char *lib_objs = NULL; |
| const char *test_lib_objs = NULL; |
| |
| chaz_MakeVar *var; |
| |
| chaz_CFlags *extra_cflags = chaz_CC_get_extra_cflags(); |
| chaz_CFlags *makefile_cflags; |
| chaz_CFlags *compile_flags; |
| chaz_CFlags *link_flags; |
| |
| printf("Creating Makefile...\n"); |
| |
| /* Directories */ |
| |
| chaz_MakeFile_add_var(self->makefile, "BASE_DIR", self->base_dir); |
| |
| /* C compiler */ |
| |
| makefile_cflags = chaz_CC_new_cflags(); |
| |
| chaz_CFlags_enable_optimization(makefile_cflags); |
| chaz_CFlags_enable_debugging(makefile_cflags); |
| chaz_CFlags_disable_strict_aliasing(makefile_cflags); |
| if (chaz_CLI_defined(self->cli, "enable-coverage")) { |
| chaz_CFlags_enable_code_coverage(makefile_cflags); |
| } |
| |
| chaz_CFlags_add_include_dir(makefile_cflags, "."); |
| chaz_CFlags_add_include_dir(makefile_cflags, self->core_dir); |
| if (self->host_src_dir) { |
| chaz_CFlags_add_include_dir(makefile_cflags, self->host_src_dir); |
| } |
| chaz_CFlags_add_include_dir(makefile_cflags, self->autogen_inc_dir); |
| |
| var = chaz_MakeFile_add_var(self->makefile, "CFLAGS", NULL); |
| chaz_MakeVar_append(var, chaz_CFlags_get_string(extra_cflags)); |
| chaz_MakeVar_append(var, chaz_CFlags_get_string(makefile_cflags)); |
| chaz_MakeVar_append(var, chaz_CC_get_cflags()); |
| |
| chaz_CFlags_destroy(makefile_cflags); |
| |
| /* Core library. */ |
| |
| if (is_c || strcmp(host, "perl") == 0) { |
| /* Shared library for C and Perl. */ |
| |
| chaz_MakeFile_add_rule(self->makefile, "all", |
| "$(CLOWNFISH_SHARED_LIB)"); |
| |
| self->lib = chaz_MakeFile_add_shared_lib(self->makefile, NULL, |
| "clownfish", cfish_version, |
| cfish_major_version, is_c); |
| lib_objs = "$(CLOWNFISH_SHARED_LIB_OBJS)"; |
| |
| compile_flags = chaz_MakeBinary_get_compile_flags(self->lib); |
| chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL); |
| |
| link_flags = chaz_MakeBinary_get_link_flags(self->lib); |
| chaz_CFlags_enable_debugging(link_flags); |
| chaz_CFlags_append(link_flags, |
| chaz_CFlags_get_string(extra_link_flags)); |
| } |
| else { |
| /* Static library for Go and Python. */ |
| |
| chaz_MakeFile_add_rule(self->makefile, "static", |
| "$(CLOWNFISH_STATIC_LIB)" |
| " $(TESTCFISH_STATIC_LIB)"); |
| |
| self->lib = chaz_MakeFile_add_static_lib(self->makefile, NULL, |
| "clownfish", 0); |
| lib_objs = "$(CLOWNFISH_STATIC_LIB_OBJS)"; |
| |
| if (strcmp(host, "python") == 0) { |
| /* For Python, the static library is linked into a shared |
| * library. |
| */ |
| compile_flags = chaz_MakeBinary_get_compile_flags(self->lib); |
| if (chaz_CC_is_msvc()) { |
| /* Python uses /MT. */ |
| chaz_CFlags_append(compile_flags, "/MT"); |
| } |
| else { |
| chaz_CFlags_compile_shared_library(compile_flags); |
| } |
| chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL); |
| /* Test code isn't separated yet. */ |
| chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL); |
| } |
| } |
| |
| if (self->host_src_dir) { |
| chaz_MakeBinary_add_src_dir(self->lib, self->host_src_dir); |
| } |
| chaz_MakeBinary_add_src_dir(self->lib, self->core_dir); |
| chaz_MakeBinary_add_src_file(self->lib, self->autogen_src_dir, |
| "cfish_parcel.c"); |
| |
| /* Test library. */ |
| |
| if (is_c || strcmp(host, "perl") == 0) { |
| /* Shared library for C and Perl. */ |
| |
| self->test_lib |
| = chaz_MakeFile_add_shared_lib(self->makefile, NULL, "testcfish", |
| cfish_version, cfish_major_version, |
| 0); |
| test_lib_objs = "$(TESTCFISH_SHARED_LIB_OBJS)"; |
| |
| compile_flags = chaz_MakeBinary_get_compile_flags(self->test_lib); |
| chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL); |
| |
| link_flags = chaz_MakeBinary_get_link_flags(self->test_lib); |
| chaz_CFlags_enable_debugging(link_flags); |
| chaz_CFlags_append(link_flags, |
| chaz_CFlags_get_string(extra_link_flags)); |
| chaz_CFlags_add_shared_lib(link_flags, NULL, "clownfish", |
| cfish_major_version); |
| |
| chaz_MakeBinary_add_prereq(self->test_lib, "$(CLOWNFISH_SHARED_LIB)"); |
| } |
| else { |
| /* Static library for Go and Python. */ |
| |
| self->test_lib = chaz_MakeFile_add_static_lib(self->makefile, NULL, |
| "testcfish", 0); |
| test_lib_objs = "$(TESTCFISH_STATIC_LIB_OBJS)"; |
| |
| if (strcmp(host, "python") == 0) { |
| /* For Python, the static library is linked into a shared |
| * library. |
| */ |
| compile_flags = chaz_MakeBinary_get_compile_flags(self->test_lib); |
| if (chaz_CC_is_msvc()) { |
| /* Python uses /MT. */ |
| chaz_CFlags_append(compile_flags, "/MT"); |
| } |
| else { |
| chaz_CFlags_compile_shared_library(compile_flags); |
| } |
| chaz_CFlags_add_define(compile_flags, "CFP_TESTCFISH", NULL); |
| /* Test code isn't separated yet. */ |
| chaz_CFlags_add_define(compile_flags, "CFP_CFISH", NULL); |
| } |
| } |
| |
| chaz_MakeBinary_add_src_dir(self->test_lib, self->test_dir); |
| chaz_MakeBinary_add_src_file(self->test_lib, self->autogen_src_dir, |
| "testcfish_parcel.c"); |
| |
| /* Additional rules. */ |
| |
| /* Object files depend on autogenerated headers. */ |
| chaz_MakeFile_add_rule(self->makefile, lib_objs, self->autogen_target); |
| chaz_MakeFile_add_rule(self->makefile, test_lib_objs, |
| self->autogen_target); |
| |
| if (is_c) { |
| cfish_MakeFile_write_c_cfc_rules(self); |
| cfish_MakeFile_write_c_test_rules(self); |
| cfish_MakeFile_write_c_install_rules(self); |
| } |
| |
| /* Targets to compile object files for Perl. */ |
| if (strcmp(host, "perl") == 0) { |
| char *objects; |
| |
| chaz_MakeFile_add_rule(self->makefile, "core_objects", |
| "$(CLOWNFISH_SHARED_LIB_OBJS)"); |
| objects = chaz_MakeBinary_obj_string(self->lib); |
| chaz_ConfWriter_add_def("CORE_OBJECTS", objects); |
| free(objects); |
| |
| chaz_MakeFile_add_rule(self->makefile, "test_objects", |
| "$(TESTCFISH_SHARED_LIB_OBJS)"); |
| objects = chaz_MakeBinary_obj_string(self->test_lib); |
| chaz_ConfWriter_add_def("TEST_OBJECTS", objects); |
| free(objects); |
| } |
| |
| chaz_MakeFile_write(self->makefile); |
| } |
| |
| static void |
| cfish_MakeFile_write_c_cfc_rules(cfish_MakeFile *self) { |
| static const char *const autogen_src_files[] = { |
| "cfish_parcel.c", |
| "testcfish_parcel.c", |
| NULL |
| }; |
| |
| chaz_MakeRule *rule; |
| |
| const char *dir_sep = chaz_OS_dir_sep(); |
| const char *exe_ext = chaz_OS_exe_ext(); |
| |
| char *cfc_dir; |
| char *cfc_exe; |
| char *cfc_command; |
| |
| int i; |
| |
| cfc_dir = chaz_Util_join(dir_sep, self->base_dir, "..", "compiler", "c", |
| NULL); |
| cfc_exe = chaz_Util_join("", cfc_dir, dir_sep, "cfc", exe_ext, NULL); |
| |
| rule = chaz_MakeFile_add_rule(self->makefile, cfc_exe, NULL); |
| chaz_MakeRule_add_make_command(rule, cfc_dir, NULL); |
| |
| self->cfh_var = chaz_MakeFile_add_var(self->makefile, "CLOWNFISH_HEADERS", |
| NULL); |
| chaz_Make_list_files(self->core_dir, "cfh", S_cfh_file_callback, self); |
| chaz_Make_list_files(self->test_dir, "cfh", S_cfh_file_callback, self); |
| |
| rule = chaz_MakeFile_add_rule(self->makefile, self->autogen_target, |
| cfc_exe); |
| chaz_MakeRule_add_prereq(rule, "$(CLOWNFISH_HEADERS)"); |
| cfc_command = chaz_Util_join("", cfc_exe, " --charmonic --source=", |
| self->core_dir, " --source=", self->test_dir, |
| " --dest=autogen --header=cfc_header", NULL); |
| chaz_MakeRule_add_command(rule, cfc_command); |
| |
| /* Tell make how autogenerated source files are built. */ |
| for (i = 0; autogen_src_files[i] != NULL; ++i) { |
| char *path = chaz_Util_join(dir_sep, self->autogen_src_dir, |
| autogen_src_files[i], NULL); |
| chaz_MakeFile_add_rule(self->makefile, path, self->autogen_target); |
| free(path); |
| } |
| |
| rule = chaz_MakeFile_clean_rule(self->makefile); |
| chaz_MakeRule_add_recursive_rm_command(rule, "autogen"); |
| chaz_MakeRule_add_make_command(rule, cfc_dir, "clean"); |
| |
| rule = chaz_MakeFile_distclean_rule(self->makefile); |
| chaz_MakeRule_add_make_command(rule, cfc_dir, "distclean"); |
| |
| free(cfc_dir); |
| free(cfc_exe); |
| free(cfc_command); |
| } |
| |
| static void |
| cfish_MakeFile_write_c_test_rules(cfish_MakeFile *self) { |
| chaz_MakeBinary *exe; |
| chaz_CFlags *link_flags; |
| chaz_MakeRule *rule; |
| |
| exe = chaz_MakeFile_add_exe(self->makefile, "t", "test_cfish", 0); |
| chaz_MakeBinary_add_src_file(exe, "t", "test_cfish.c"); |
| |
| link_flags = chaz_MakeBinary_get_link_flags(exe); |
| chaz_CFlags_add_rpath(link_flags, "\"$$PWD\""); |
| chaz_CFlags_add_shared_lib(link_flags, NULL, "testcfish", |
| cfish_major_version); |
| chaz_CFlags_add_shared_lib(link_flags, NULL, "clownfish", |
| cfish_major_version); |
| |
| chaz_MakeBinary_add_prereq(exe, "$(TESTCFISH_SHARED_LIB)"); |
| chaz_MakeBinary_add_prereq(exe, "$(CLOWNFISH_SHARED_LIB)"); |
| |
| chaz_MakeFile_add_rule(self->makefile, "$(TEST_CFISH_EXE_OBJS)", |
| self->autogen_target); |
| |
| rule = chaz_MakeFile_add_rule(self->makefile, "test", "$(TEST_CFISH_EXE)"); |
| chaz_MakeRule_add_command(rule, "$(TEST_CFISH_EXE)"); |
| |
| if (chaz_OS_shell_type() == CHAZ_OS_POSIX) { |
| rule = chaz_MakeFile_add_rule(self->makefile, "valgrind", |
| "$(TEST_CFISH_EXE)"); |
| chaz_MakeRule_add_command(rule, |
| "valgrind --leak-check=full" |
| " $(TEST_CFISH_EXE)"); |
| } |
| |
| if (chaz_CLI_defined(self->cli, "enable-coverage")) { |
| rule = chaz_MakeFile_add_rule(self->makefile, "coverage", |
| "$(TEST_CFISH_EXE)"); |
| chaz_MakeRule_add_command(rule, |
| "lcov" |
| " --zerocounters" |
| " --directory $(BASE_DIR)"); |
| chaz_MakeRule_add_command(rule, "$(TEST_CFISH_EXE)"); |
| chaz_MakeRule_add_command(rule, |
| "lcov" |
| " --capture" |
| " --directory $(BASE_DIR)" |
| " --base-directory ." |
| " --rc lcov_branch_coverage=1" |
| " --output-file clownfish.info"); |
| chaz_MakeRule_add_command(rule, |
| "lcov" |
| " --remove clownfish.info" |
| " '/usr/include/*'" |
| " 'c/autogen/*'" |
| " 'core/Clownfish/Test.*'" |
| " 'core/Clownfish/Test/*'" |
| " 'core/TestClownfish.*'" |
| " --rc lcov_branch_coverage=1" |
| " --output-file clownfish.info"); |
| chaz_MakeRule_add_command(rule, |
| "genhtml" |
| " --branch-coverage" |
| " --output-directory coverage" |
| " clownfish.info"); |
| |
| rule = chaz_MakeFile_clean_rule(self->makefile); |
| chaz_MakeRule_add_rm_command(rule, "clownfish.info"); |
| chaz_MakeRule_add_recursive_rm_command(rule, "coverage"); |
| } |
| } |
| |
| static void |
| cfish_MakeFile_write_c_install_rules(cfish_MakeFile *self) { |
| const char *dir_sep = chaz_OS_dir_sep(); |
| char *src; |
| |
| src = chaz_Util_join(dir_sep, "autogen", "share", NULL); |
| chaz_MakeFile_install_dir(self->makefile, src, "$(DATADIR)", NULL); |
| free(src); |
| |
| src = chaz_Util_join(dir_sep, "autogen", "man", NULL); |
| chaz_MakeFile_install_dir(self->makefile, src, "$(MANDIR)", NULL); |
| free(src); |
| |
| chaz_MakeFile_install_pkgconfig(self->makefile, "clownfish", cfish_version, |
| "Name: Clownfish\n" |
| "Description: Symbiotic object system\n" |
| "URL: http://lucy.apache.org/\n" |
| "Version: $${version}\n" |
| "Libs: -L$${libdir} -lclownfish\n" |
| ); |
| } |
| |
| static void |
| S_cfh_file_callback(const char *dir, char *file, void *context) { |
| cfish_MakeFile *self = (cfish_MakeFile*)context; |
| const char *dir_sep = chaz_OS_dir_sep(); |
| char *cfh_file; |
| |
| if (!S_ends_with(file, ".cfh")) { |
| chaz_Util_warn("Unexpected Clownfish header filename: %s", file); |
| return; |
| } |
| |
| cfh_file = chaz_Util_join(dir_sep, dir, file, NULL); |
| chaz_MakeVar_append(self->cfh_var, cfh_file); |
| free(cfh_file); |
| } |
| |
| static int |
| S_ends_with(const char *string, const char *postfix) { |
| size_t len = strlen(string); |
| size_t postfix_len = strlen(postfix); |
| return len >= postfix_len |
| && memcmp(string + len - postfix_len, postfix, postfix_len) == 0; |
| } |
| |
| static int |
| S_need_libpthread(chaz_CLI *cli) { |
| static const char source[] = |
| "#include <pthread.h>\n" |
| "\n" |
| "int main() {\n" |
| " pthread_create(0, 0, 0, 0);\n" |
| " pthread_key_create(0, 0);\n" |
| " return 0;\n" |
| "}\n"; |
| chaz_CFlags *temp_cflags; |
| |
| if (chaz_CLI_defined(cli, "disable-threads") |
| || chaz_HeadCheck_check_header("windows.h") |
| ) { |
| return 0; |
| } |
| |
| if (!chaz_HeadCheck_check_header("pthread.h")) { |
| chaz_Util_die("pthread.h not found. Try --disable-threads."); |
| } |
| |
| if (chaz_CC_test_link(source)) { |
| return 0; |
| } |
| |
| temp_cflags = chaz_CC_get_temp_cflags(); |
| chaz_CFlags_add_external_lib(temp_cflags, "pthread"); |
| if (!chaz_CC_test_link(source)) { |
| chaz_Util_die("Can't link with libpthread. Try --disable-threads."); |
| } |
| chaz_CFlags_clear(temp_cflags); |
| |
| return 1; |
| } |
| |