diff --git a/.gitignore b/.gitignore index 781ba3860..95911a8bf 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ # Automatically generated files COPYING INSTALL +include/config.h # Temporary *.swp @@ -44,3 +45,12 @@ cscope.* lcov CMAKE_BINARY_DIR + +# Generated Rust Bindings +bindings.rs + +# Cargo lock file +Cargo.lock + +# Cargo build path +target diff --git a/.travis.yml b/.travis.yml index 41c2b344e..46c0ecd39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,132 +1,57 @@ sudo: false language: c +dist: bionic # using anchor to import sources into linux builds addons: apt: &apt sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 - - llvm-toolchain-precise-3.7 - - llvm-toolchain-precise # important for allowed-to-fail matching # see https://docs.travis-ci.com/user/customizing-the-build#Rows-that-are-Allowed-to-Fail env: - - ALLOWED_TO_FAIL=0 + global: + - MAKEFLAGS="-j 2" # travis currently does not support directly setting gcc/clang with versions # (e.g. gcc-4.8) as value for the compiler key. So we will have to manually # request these packages and use environment varibles to create the matrix. -# -# In the case of osx, use brew to install the paritcular versions, instead of -# specifying with packages. -matrix: +jobs: + fast_finish: true include: - # gcc 4.8 on linux - - env: - - C_COMPILER=gcc-4.8 - addons: - apt: - <<: *apt - packages: - - gcc-4.8 - - libsubunit-dev + - name: "gcc-7 on Linux" + compiler: gcc - - # gcc 4.9 on linux - - env: - - C_COMPILER=gcc-4.9 - addons: - apt: - <<: *apt - packages: - - gcc-4.9 - - libsubunit-dev - - # gcc 5 on linux - - env: - - C_COMPILER=gcc-5 - addons: - apt: - <<: *apt - packages: - - gcc-5 - - libsubunit-dev - - # gcc 5 on linux - - env: - - C_COMPILER=gcc-5 + - name: "gcc-7 on Linux, Rust enabled" + compiler: gcc + env: - RUST_ENABLED=1 - addons: - apt: - <<: *apt - packages: - - gcc-5 - - libsubunit-dev - - # clang 3.6 on linux - - env: - - C_COMPILER=clang-3.6 - addons: - apt: - <<: *apt - packages: - - clang-3.6 - - libsubunit-dev - - # clang 3.7 on linux - - env: - - C_COMPILER=clang-3.7 - addons: - apt: - <<: *apt - packages: - - clang-3.7 - - libsubunit-dev - ## gcc 4.8 on osx - #- os: osx - # env: FORMULA=gcc48 COMPILER=gcc C_COMPILER=gcc-4.8 - # - ## gcc 4.9 on osx - #- os: osx - # env: FORMULA=gcc49 COMPILER=gcc C_COMPILER=gcc-4.9 - # - ## gcc 5 on osx - #- os: osx - # env: FORMULA=gcc5 COMPILER=gcc C_COMPILER=gcc-5 + - name: "cargo build" + language: rust + script: + - ./ci/cargo.sh - # OSX 10.13 - # Apple LLVM version 9.1.0 (clang-902.0.39.2) - # Target: x86_64-apple-darwin17.6.0 - os: osx - osx_image: xcode9.4 - env: - - C_COMPILER=clang - - ALLOWED_TO_FAIL=1 + osx_image: xcode11.4 + compiler: clang - # OSX 10.12 - # Apple LLVM version 9.0.0 (clang-900.0.39.2) - # Target: x86_64-apple-darwin16.7.0 - os: osx - osx_image: xcode9.2 - env: - - C_COMPILER=clang - - ALLOWED_TO_FAIL=1 + osx_image: xcode11.4 + language: rust + script: + - ./ci/cargo.sh allow_failures: - os: osx - osx_image: xcode9.4 - env: - - C_COMPILER=clang - - ALLOWED_TO_FAIL=1 - + osx_image: xcode11.4 + compiler: clang - os: osx - osx_image: xcode9.2 - env: - - C_COMPILER=clang - - ALLOWED_TO_FAIL=1 + osx_image: xcode11.4 + language: rust + script: + - ./ci/cargo.sh before_install: - ./ci/before-install.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d2a2c05a..f17e543cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.0) project(ccommon C) -enable_testing() +# Uncomment the following to output dependency graph debugging messages +# set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1) ################### # detect platform # @@ -36,8 +37,8 @@ endif() # config.h.in has to include entries set/tested here for them to have effect # version info -set(${PROJECT_NAME}_VERSION_MAJOR 1) -set(${PROJECT_NAME}_VERSION_MINOR 2) +set(${PROJECT_NAME}_VERSION_MAJOR 2) +set(${PROJECT_NAME}_VERSION_MINOR 1) set(${PROJECT_NAME}_VERSION_PATCH 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH} @@ -51,60 +52,35 @@ option(HAVE_ASSERT_LOG "assert_log enabled by default" ON) option(HAVE_ASSERT_PANIC "assert_panic disabled by default" OFF) option(HAVE_LOGGING "logging enabled by default" ON) option(HAVE_STATS "stats enabled by default" ON) +option(HAVE_TEST "test built by default" ON) option(HAVE_DEBUG_MM "debugging oriented memory management disabled by default" OFF) -option(COVERAGE "code coverage" OFF) +option(HAVE_COVERAGE "code coverage" OFF) option(HAVE_RUST "rust bindings not built by default" OFF) +option(HAVE_ITT_INSTRUMENTATION "instrument code with ITT API" OFF) + +option(FORCE_CHECK_BUILD "Force building check with ci/install-check.sh" OFF) if(HAVE_RUST) option(RUST_VERBOSE_BUILD "pass -vv to cargo compilation" OFF) endif() -if(BUILD_AND_INSTALL_CHECK) - # (simms) What follows is a crime against build systems as we run the build/install - # for the check library up front, during the planning phase. - - set(LIBCHECK_PREFIX "${CMAKE_BINARY_DIR}/check") - - # check for a local install of check - if(NOT EXISTS "${LIBCHECK_PREFIX}") - # (simms) This is terrible and I did it this way to ensure this gets built - # before the rest of the 'check' tests run. This should be rewritten so that - # the other dependencies know that there's a target that can build check - execute_process( - COMMAND "bash" "${PROJECT_SOURCE_DIR}/ci/install-check.sh" "${LIBCHECK_PREFIX}" - TIMEOUT 300 # if this doesn't build in 5 minutes something is hosed - ) - endif() - - set(CHECK_ROOT_DIR "${LIBCHECK_PREFIX}") - set(CMAKE_REQUIRED_INCLUDES "${CHECK_ROOT_DIR}/include") # these make check link correctly in ccommon and pelikan - set(CMAKE_REQUIRED_LIBRARIES "${CHECK_ROOT_DIR}/lib") -endif() - include(CheckIncludeFiles) if(OS_PLATFORM STREQUAL "OS_LINUX") check_include_files(linux/time64.h HAVE_TIME64) endif() -include(CheckIncludeFiles) -if(OperatingSystem STREQUAL "OS_LINUX") - check_include_files(linux/time64.h HAVE_TIME64) -endif() - include(CheckSymbolExists) check_symbol_exists(sys_signame signal.h HAVE_SIGNAME) include(CheckFunctionExists) check_function_exists(backtrace HAVE_BACKTRACE) - -include(TestBigEndian) -test_big_endian(HAVE_BIG_ENDIAN) +check_function_exists(accept4 HAVE_ACCEPT4) # how to use config.h.in to generate config.h # this has to be set _after_ the above checks configure_file( "${PROJECT_SOURCE_DIR}/config.h.in" - "${PROJECT_BINARY_DIR}/config.h") + "${PROJECT_SOURCE_DIR}/include/config.h") ########################## @@ -112,46 +88,98 @@ configure_file( ########################## # set compiler flags -# string concat is easier in 3.0, but older versions don't have the concat subcommand -# so we are using list as input until we move to new version -# TODO add build types + add_definitions(-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64) + +# Set a default build type (Release) if none was specified +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +if(CMAKE_BUILD_TYPE MATCHES Debug) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") +endif() + set(CMAKE_MACOSX_RPATH 1) -set(CFLAGS_LIST +string(CONCAT CFLAGS "-std=c11 " - "-ggdb3 -O2 " + "-ggdb3 " "-Wall " "-Wmissing-prototypes -Wmissing-declarations -Wredundant-decls " "-Wunused-function -Wunused-value -Wunused-variable " "-fstrict-aliasing ") -string(REPLACE "" "" CFLAGS ${CFLAGS_LIST}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CFLAGS}") if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--no-as-needed -ldl -pthread -fPIC") endif() -if (COVERAGE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -W -fprofile-arcs -ftest-coverage") -endif(COVERAGE) - -# test dependencies include(FindPackageHandleStandardArgs) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") -find_package(Check) -if(NOT CHECK_FOUND) - message(WARNING "Check is required to build and run tests") -endif(NOT CHECK_FOUND) -if(CHECK_FOUND) - check_symbol_exists(ck_assert_int_eq check.h CHECK_WORKING) - if(NOT CHECK_WORKING) - message(WARNING "Check version too old to build tests") - endif(NOT CHECK_WORKING) -endif(CHECK_FOUND) +# test dependencies +if (HAVE_TEST) + enable_testing() + # first we try default ways of finding gmodules + find_package(CHECK) + if(CHECK_FOUND) + check_symbol_exists(ck_assert_int_eq check.h CHECK_WORKING) + endif(CHECK_FOUND) + # if we don't have a working version of check, build it + if(NOT CHECK_WORKING OR FORCE_CHECK_BUILD) + set(LIBCHECK_PREFIX "${CMAKE_BINARY_DIR}/check") + execute_process( + COMMAND "bash" "${PROJECT_SOURCE_DIR}/ci/install-check.sh" "${LIBCHECK_PREFIX}" + TIMEOUT 300 # if this doesn't build in 5 minutes something is hosed + RESULT_VARIABLE LIBCHECK_RETCODE + ) + if(LIBCHECK_RETCODE) # non-zero means error + message(STATUS "build libcheck failed, return code: " ${LIBCHECK_RETCODE}) + else(LIBCHECK_RETCODE) + # use locally built libcheck + set(CHECK_ROOT_DIR "${LIBCHECK_PREFIX}") + find_package(CHECK) + endif(LIBCHECK_RETCODE) + endif(NOT CHECK_WORKING OR FORCE_CHECK_BUILD) + + # use fluxcapacitor to mock time + if(OS_PLATFORM STREQUAL "OS_LINUX") + set(FLUXCAP_PREFIX "${CMAKE_BINARY_DIR}/fluxcapacitor") + execute_process( + COMMAND "bash" "${PROJECT_SOURCE_DIR}/ci/install-fluxcapacitor.sh" "${FLUXCAP_PREFIX}" + TIMEOUT 60 # if this doesn't build in 60 seconds something is hosed + RESULT_VARIABLE FLUXCAP_RETCODE + ) + if(FLUXCAP_RETCODE) # non-zero means error + message(STATUS "build fluxcapacitor failed, return code: " ${FLUXCAP_RETCODE}) + else(FLUXCAP_RETCODE) + set(FLUXCAP_BINARY "${FLUXCAP_PREFIX}/fluxcapacitor") + message(STATUS "fluxcapacitor available at: " ${FLUXCAP_BINARY}) + endif(FLUXCAP_RETCODE) + endif(OS_PLATFORM STREQUAL "OS_LINUX") +endif(HAVE_TEST) + +if (HAVE_ITT_INSTRUMENTATION) + if(PKG_CONFIG_FOUND) + pkg_check_modules(ITTNOTIFY REQUIRED ittnotify>=1.0) + else() + find_package(ITTNOTIFY REQUIRED 1.0) + endif() + include_directories(${ITTNOTIFY_INCLUDE_DIRS}) + link_directories(${ITTNOTIFY_LIBRARY_DIRS}) + link_libraries(${ITTNOTIFY_LIBRARIES}) +endif(HAVE_ITT_INSTRUMENTATION) find_package(Threads) +if (HAVE_COVERAGE) + if(NOT ${CMAKE_BUILD_TYPE} MATCHES Debug) + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading" ) + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") +endif(HAVE_COVERAGE) # where to find include files include_directories( @@ -159,36 +187,75 @@ include_directories( "${PROJECT_BINARY_DIR}" "include") -if(HAVE_RUST) - enable_language(Rust) - include(CMakeCargo) - add_subdirectory(rust) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_RUST=1") -endif() - - ################### # things to build # ################### add_subdirectory(src) -if(CHECK_WORKING) - include_directories(${include_directories} "${CHECK_INCLUDES}") + +if(HAVE_TEST) + include_directories(${include_directories} ${CHECK_INCLUDES}) add_subdirectory(test) -endif(CHECK_WORKING) +endif(HAVE_TEST) + +if(HAVE_RUST) + include(CMakeCargo) + add_subdirectory(rust) + + if (${CMAKE_VERSION} VERSION_LESS "3.13.0") + # CMakeCargo requires the use of some newer features of cmake + # for changes to dependant libraries to cause a rebuild. This + # will never break the build, it is just annoying for development. + # Leave a warning here, but don't break the build for older cmake + # versions. + message( + WARNING + "Rust targets don't properly pick up changes to dependencies in cmake version <= 3.13" + ) + endif() +endif() ################### # print a summary # ################### +message(STATUS "<<++=====------------------\\/------------------=====++>>") +message(STATUS "<<++ ccommon summary ++>>") +message(STATUS "<<++=====------------------/\\------------------=====++>>") +message(STATUS "=============CMake related=============") +message(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE}) message(STATUS "PLATFORM: " ${OS_PLATFORM}) - message(STATUS "CPPFLAGS: " ${CMAKE_CPP_FLAGS}) message(STATUS "CFLAGS: " ${CMAKE_C_FLAGS}) +message(STATUS "=======================================") +message(STATUS "=======Status of system features=======") message(STATUS "HAVE_SIGNAME: " ${HAVE_SIGNAME}) - message(STATUS "HAVE_BACKTRACE: " ${HAVE_BACKTRACE}) -message(STATUS "HAVE_BIG_ENDIAN: " ${HAVE_BIG_ENDIAN}) - -message(STATUS "CHECK_WORKING: " ${CHECK_WORKING}) +message(STATUS "HAVE_ACCEPT4: " ${HAVE_ACCEPT4}) +if(OS_PLATFORM STREQUAL "OS_LINUX") + message(STATUS "HAVE_TIME64: " ${HAVE_TIME64}) +endif() +message(STATUS "=======================================") + +message(STATUS "======Status of optional features======") +message(STATUS "HAVE_RUST: " ${HAVE_RUST}) +message(STATUS "HAVE_ASSERT_LOG: " ${HAVE_ASSERT_LOG}) +message(STATUS "HAVE_ASSERT_PANIC: " ${HAVE_ASSERT_PANIC}) +message(STATUS "HAVE_LOGGING: " ${HAVE_LOGGING}) +message(STATUS "HAVE_STATS: " ${HAVE_STATS}) +message(STATUS "HAVE_ITT_INSTRUMENTATION: " ${HAVE_ITT_INSTRUMENTATION}) +message(STATUS "HAVE_DEBUG_MM: " ${HAVE_DEBUG_MM}) +message(STATUS "HAVE_TEST: " ${HAVE_TEST}) +message(STATUS "HAVE_COVERAGE: " ${HAVE_COVERAGE}) +message(STATUS "=======================================") + + +if(DUMP_ALL) + message(STATUS "<<++=====------------------\\/------------------=====++>>") + get_cmake_property(_variableNames VARIABLES) + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "<<++=====------------------/\\------------------=====++>>") +endif() diff --git a/LICENSE b/LICENSE index ecc06d346..5c3aef4f8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright 2013-2015 Twitter, Inc +Copyright 2013-2018 Twitter, Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/NOTICE b/NOTICE index 2b7bb058e..e0672064d 100644 --- a/NOTICE +++ b/NOTICE @@ -22,3 +22,5 @@ * Boston, MA 02111-1307, USA. */ +We use the CMakeRust project (https://github.com/Devolutions/CMakeRust) under +the Apache 2.0 License. diff --git a/ci/before-install.sh b/ci/before-install.sh index cff9327c3..b5f49421a 100755 --- a/ci/before-install.sh +++ b/ci/before-install.sh @@ -11,21 +11,6 @@ trap cleanup EXIT TOPLEVEL="$(git -C "$(cd "$(dirname "$0")" >/dev/null || exit 1; pwd)" rev-parse --show-toplevel)" || die 'failed to find TOPLEVEL' -# for osx: 0. update brew; 1. install cmake if missing; 2. (gcc) unlink pre-installed gcc; 3. (gcc) install desired version of gcc - -if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update &>/dev/null - brew install cmake || true # xcode 8.1 is missing cmake - - if [[ "$C_COMPILER" =~ ^gcc && -n "${FORMULA:-}" ]]; then - brew unlink gcc || true - brew unlink "$FORMULA" || true - brew install "$FORMULA" - fi -fi - -export CC="$C_COMPILER" - if [[ -n "${RUST_ENABLED:-}" ]]; then curl https://sh.rustup.rs -sSf | sh -s -- -y fi diff --git a/ci/cargo.sh b/ci/cargo.sh new file mode 100755 index 000000000..8a8c25725 --- /dev/null +++ b/ci/cargo.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -uo pipefail +IFS=$'\n\t' + +# Cargo currently does not allow nested workspaces. Since this repo is vendored +# into github.com/twitter/pelikan which is itself a workspace, we cannot commit +# a workspace manifest for this repository. Cargo tracking issue: +# https://github.com/rust-lang/cargo/issues/5042 + +# As a workaround, we can construct a workspace manifest before running the +# build. This allows the crates within this repo to share build artifacts. + +### +# Create workspace manifest +### + +cat > Cargo.toml <
> Cargo.toml +done + +cat >> Cargo.toml <