blob: 49c9c6f92fb78d0c96ab19dd28a72771b848236c [file] [log] [blame]
/* 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.1";
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
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_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_Probe_gcc_version_num()) {
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_Probe_msvc_version_num()) {
if (chaz_Probe_msvc_version_num() < 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");
if (chaz_Probe_msvc_version_num() < 1300) {
/* Redefine 'for' to fix broken 'for' scoping under MSVC6. */
chaz_CFlags_append(extra_cflags, "/Dfor=\"if(0);else for\"");
}
}
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 *dir_sep = chaz_OS_dir_sep();
const char *host = chaz_CLI_strval(self->cli, "host");
const char *lib_objs = NULL;
const char *test_lib_objs = NULL;
chaz_MakeVar *var;
chaz_MakeRule *rule;
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 */
chaz_MakeFile_add_var(self->makefile, "CC", chaz_CC_get_cc());
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 (strcmp(host, "c") == 0 || 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);
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");
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_msvc_version_num()) {
/* 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 (strcmp(host, "c") == 0 || 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);
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");
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_msvc_version_num()) {
/* 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 (strcmp(host, "c") == 0) {
cfish_MakeFile_write_c_cfc_rules(self);
cfish_MakeFile_write_c_test_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_CC_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, " --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");
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) {
const char *valgrind_command;
rule = chaz_MakeFile_add_rule(self->makefile, "valgrind",
"$(TEST_CFISH_EXE)");
if (chaz_CC_binary_format() == CHAZ_CC_BINFMT_ELF) {
valgrind_command = "LD_LIBRARY_PATH=. CLOWNFISH_VALGRIND=1"
" valgrind"
" --leak-check=full"
" $(TEST_CFISH_EXE)";
}
else {
valgrind_command = "CLOWNFISH_VALGRIND=1"
" valgrind"
" --leak-check=full"
" $(TEST_CFISH_EXE)";
}
chaz_MakeRule_add_command(rule, valgrind_command);
}
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
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;
}