diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0f03fdb9..41646f79e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,11 +5,8 @@ on: [push, pull_request] jobs: linter: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - name: Install clang-tidy run: | @@ -23,7 +20,6 @@ jobs: CXX: clang++ linux: - runs-on: ubuntu-latest strategy: fail-fast: false @@ -45,6 +41,7 @@ jobs: - uses: actions/checkout@v1 - name: Install valgrind run: | + sudo apt update sudo apt install -y valgrind - name: Build and test run: | @@ -53,7 +50,6 @@ jobs: make leakcheck macos: - runs-on: macOS-latest strategy: fail-fast: false diff --git a/CMakeLists.txt b/CMakeLists.txt index b3edd749d..8371c43a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,18 +1,30 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0063 NEW) +cmake_policy(SET CMP0065 NEW) + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") + project(cmark VERSION 0.29.0) -include("FindAsan.cmake") +include(TargetProperties) +include(FindAsan) include(GNUInstallDirs) if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") - message(FATAL_ERROR "Do not build in-source.\nPlease remove CMakeCache.txt and the CMakeFiles/ directory.\nThen: mkdir build ; cd build ; cmake .. ; make") + message(FATAL_ERROR "Do not build in-source.\nPlease remove CMakeCache.txt and the CMakeFiles/ directory.\nThen: mkdir build ; cd build ; cmake .. ; make") endif() option(CMARK_TESTS "Build cmark tests and enable testing" ON) option(CMARK_STATIC "Build static libcmark library" ON) option(CMARK_SHARED "Build shared libcmark library" ON) +option(CMARK_EXE "Build cmark executable" ON) option(CMARK_LIB_FUZZER "Build libFuzzer fuzzing harness" OFF) +set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES};Release;Profile;Asan;Ubsan" CACHE STRING "" FORCE) +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE) +endif(NOT CMAKE_BUILD_TYPE) + if(NOT MSVC) set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD_REQUIRED YES) @@ -21,56 +33,16 @@ endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) -# The Linux modules distributed with CMake add "-rdynamic" to the build flags -# which is incompatible with static linking under certain configurations. -# Unsetting CMAKE_SHARED_LIBRARY_LINK_C_FLAGS ensures this does not happen. -if(CMARK_STATIC AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) -endif() - -# Compiler flags -if(MSVC) - # Force to always compile with W4 - add_compile_options($<$:/W4>) - add_compile_options($<$:/wd4706>) - # Compile as C++ under MSVC older than 12.0 - if(MSVC_VERSION LESS 1800) - add_compile_options($<$:/TP>) - endif() - add_compile_options($<$:/D_CRT_SECURE_NO_WARNINGS>) -elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES Clang) - add_compile_options($<$:-Wall>) - add_compile_options($<$:-Wextra>) - add_compile_options($<$:-pedantic>) -endif() - -# Check integrity of node structure when compiled as debug -add_compile_options($<$:-DCMARK_DEBUG_NODES>) - -add_compile_options($<$,$>:-pg>) - -if(CMAKE_BUILD_TYPE STREQUAL Ubsan) - add_compile_options($<$:-fsanitize=undefined>) -endif() -if(CMARK_LIB_FUZZER) - add_compile_options($<$:-fsanitize-coverage=trace-pc-guard>) -endif() - add_subdirectory(src) -if(CMARK_TESTS AND (CMARK_SHARED OR CMARK_STATIC)) - add_subdirectory(api_test) -endif() -# TODO(compnerd) should this be enabled for MinGW, which sets CMAKE_SYSTEM_NAME -# to Windows, but defines `MINGW`. -if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows) + +if(NOT WIN32 AND NOT MINGW) add_subdirectory(man) endif() + if(CMARK_TESTS) enable_testing() + if(CMARK_SHARED OR CMARK_STATIC) + add_subdirectory(api_test) + endif() add_subdirectory(test testdir) endif() - -if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING - "Choose the type of build, options are: Debug Profile Release Asan Ubsan." FORCE) -endif(NOT CMAKE_BUILD_TYPE) diff --git a/api_test/CMakeLists.txt b/api_test/CMakeLists.txt index b8b135b33..c660f2086 100644 --- a/api_test/CMakeLists.txt +++ b/api_test/CMakeLists.txt @@ -4,8 +4,5 @@ add_executable(api_test harness.h main.c ) -if(CMARK_SHARED) - target_link_libraries(api_test cmark) -else() - target_link_libraries(api_test cmark_static) -endif() + +target_link_libraries(api_test cmark::cmark) diff --git a/FindAsan.cmake b/cmake/FindAsan.cmake similarity index 100% rename from FindAsan.cmake rename to cmake/FindAsan.cmake diff --git a/cmake/TargetProperties.cmake b/cmake/TargetProperties.cmake new file mode 100644 index 000000000..42e2917db --- /dev/null +++ b/cmake/TargetProperties.cmake @@ -0,0 +1,28 @@ +# Defines common cmark properties. +function(cmark_target_properties tgt) + # Compiler flags + if(MSVC) + target_compile_options(${tgt} PRIVATE + $<$:/W4> # Compile with W4 + $<$:/wd4706> + $<$:/D_CRT_SECURE_NO_WARNINGS> + $<$:/D_CRT_SECURE_NO_WARNINGS> + $<$,$>:/TP> + ) + elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES Clang) + target_compile_options(${tgt} PRIVATE + $<$:-Wall> + $<$:-Wextra> + $<$:-pedantic> + $<$,$>:-pg> + $<$,$>:-fsanitize=undefined> + $<$,$>:-fsanitize-coverage=trace-pc-guard> + ) + endif() + + # Compiler definitions + target_compile_definitions(${tgt} PRIVATE + $<$:CMARK_DEBUG_NODES> # Check integrity of node structure + $<$,STATIC_LIBRARY>:CMARK_STATIC_DEFINE> # Disable PUBLIC declarations + ) +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 026fd7913..4a1b86aac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,18 @@ -if(${CMAKE_VERSION} VERSION_GREATER "3.3") - cmake_policy(SET CMP0063 NEW) -endif() +include(CheckCSourceCompiles) +include(CheckIncludeFile) +include(CMakePackageConfigHelpers) +include(GenerateExportHeader) +set(PROGRAM "cmark_exe") +set(FUZZ "cmark-fuzz") set(LIBRARY "cmark") -set(STATICLIBRARY "cmark_static") -set(HEADERS +if(CMARK_SHARED) + set(STATICLIBRARY "cmark_static") +else() + set(STATICLIBRARY "cmark") +endif() + +set(LIBRARY_HEADERS cmark.h parser.h buffer.h @@ -18,7 +26,7 @@ set(HEADERS houdini.h cmark_ctype.h render.h - ) +) set(LIBRARY_SOURCES cmark.c node.c @@ -40,37 +48,32 @@ set(LIBRARY_SOURCES houdini_html_e.c houdini_html_u.c cmark_ctype.c - ${HEADERS} - ) - -set(PROGRAM "cmark_exe") + ${LIBRARY_HEADERS} +) set(PROGRAM_SOURCES main.c) +# Feature tests +check_include_file(stdbool.h HAVE_STDBOOL_H) +check_c_source_compiles( + "int main() { __builtin_expect(0,0); return 0; }" + HAVE___BUILTIN_EXPECT) +check_c_source_compiles(" + int f(void) __attribute__ (()); + int main() { return 0; } +" HAVE___ATTRIBUTE__) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in + ${CMAKE_CURRENT_BINARY_DIR}/config.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmark_version.h.in ${CMAKE_CURRENT_BINARY_DIR}/cmark_version.h) -include(GNUInstallDirs) -include (GenerateExportHeader) - -add_executable(${PROGRAM} ${PROGRAM_SOURCES}) -set_target_properties(${PROGRAM} PROPERTIES - OUTPUT_NAME "cmark") - -if (CMARK_STATIC) - target_link_libraries(${PROGRAM} ${STATICLIBRARY}) - # Disable the PUBLIC declarations when compiling the executable: - set_target_properties(${PROGRAM} PROPERTIES - COMPILE_FLAGS -DCMARK_STATIC_DEFINE) -elseif (CMARK_SHARED) - target_link_libraries(${PROGRAM} ${LIBRARY}) -endif() - # -fvisibility=hidden set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) if (CMARK_SHARED) add_library(${LIBRARY} SHARED ${LIBRARY_SOURCES}) + cmark_target_properties(${LIBRARY}) set_target_properties(${LIBRARY} PROPERTIES MACOSX_RPATH TRUE OUTPUT_NAME "cmark" @@ -78,7 +81,8 @@ if (CMARK_SHARED) PDB_NAME cmark_dll # Include minor version and patch level in soname for now. SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} - VERSION ${PROJECT_VERSION}) + VERSION ${PROJECT_VERSION} + ) target_include_directories(${LIBRARY} INTERFACE $ $ @@ -93,8 +97,8 @@ endif() if (CMARK_STATIC) add_library(${STATICLIBRARY} STATIC ${LIBRARY_SOURCES}) + cmark_target_properties(${STATICLIBRARY}) set_target_properties(${STATICLIBRARY} PROPERTIES - COMPILE_FLAGS -DCMARK_STATIC_DEFINE OUTPUT_NAME "cmark$<$:_static>" POSITION_INDEPENDENT_CODE ON VERSION ${PROJECT_VERSION}) @@ -105,6 +109,9 @@ if (CMARK_STATIC) add_library(cmark::cmark_static ALIAS ${STATICLIBRARY}) if (NOT CMARK_SHARED) + # Linking against cmark::cmark shouldn't cause errors just because shared + # builds weren't enabled. + add_library(cmark::cmark ALIAS ${STATICLIBRARY}) generate_export_header(${STATICLIBRARY} BASE_NAME ${PROJECT_NAME}) endif() @@ -112,22 +119,39 @@ if (CMARK_STATIC) list(APPEND CMARK_INSTALL ${STATICLIBRARY}) endif() -if (MSVC) - set_property(TARGET ${PROGRAM} - APPEND PROPERTY LINK_FLAGS /INCREMENTAL:NO) -endif(MSVC) +if(CMARK_EXE) + add_executable(${PROGRAM} ${PROGRAM_SOURCES}) + cmark_target_properties(${PROGRAM}) + set_target_properties(${PROGRAM} PROPERTIES OUTPUT_NAME "cmark") + + if (CMARK_STATIC) + target_link_libraries(${PROGRAM} PRIVATE ${STATICLIBRARY}) + elseif (CMARK_SHARED) + target_link_libraries(${PROGRAM} PRIVATE ${LIBRARY}) + endif() + + if (MSVC) + set_target_properties(${PROGRAM} PROPERTIES LINK_FLAGS /INCREMENTAL:NO) + endif() + + # Disables -rdynamic, which is incompatible with static linking under certain + # configurations. + set_target_properties(${PROGRAM} PROPERTIES ENABLE_EXPORTS OFF) + + list(APPEND CMARK_INSTALL ${PROGRAM}) +endif() if(NOT MSVC OR CMAKE_HOST_SYSTEM_NAME STREQUAL Windows) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) include(InstallRequiredSystemLibraries) endif() -install(TARGETS ${PROGRAM} ${CMARK_INSTALL} +install(TARGETS ${CMARK_INSTALL} EXPORT cmark-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) +) if(CMARK_SHARED OR CMARK_STATIC) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libcmark.pc.in @@ -140,58 +164,44 @@ if(CMARK_SHARED OR CMARK_STATIC) ${CMAKE_CURRENT_BINARY_DIR}/cmark_export.h ${CMAKE_CURRENT_BINARY_DIR}/cmark_version.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - ) + ) + + # `find_package` searches different paths in Windows. + if(WIN32) + set(CMAKE_INSTALL_CMAKEDIR CMake + CACHE STRING "Installation directory for CMake files") + else() + set(CMAKE_INSTALL_CMAKEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/cmark + CACHE STRING "Installation directory for CMake files") + endif() - # Include module for fuctions - # - 'write_basic_package_version_file' - # - 'configure_package_config_file' - include(CMakePackageConfigHelpers) # generate cmark-config.cmake and cmark-config-version.cmake files configure_package_config_file( "cmarkConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config.cmake" - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cmark") + INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}") write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config-version.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) # install config and version file - install( - FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config-version.cmake" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cmark" + install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config-version.cmake" + DESTINATION "${CMAKE_INSTALL_CMAKEDIR}" ) # install targets file - install( - EXPORT "cmark-targets" - NAMESPACE "cmark::" - DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cmark" + install(EXPORT cmark-targets + NAMESPACE cmark:: + DESTINATION "${CMAKE_INSTALL_CMAKEDIR}" ) - endif() -# Feature tests -include(CheckIncludeFile) -include(CheckCSourceCompiles) -CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) -CHECK_C_SOURCE_COMPILES( - "int main() { __builtin_expect(0,0); return 0; }" - HAVE___BUILTIN_EXPECT) -CHECK_C_SOURCE_COMPILES(" - int f(void) __attribute__ (()); - int main() { return 0; } -" HAVE___ATTRIBUTE__) - -CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h) - if(CMARK_LIB_FUZZER) - add_executable(cmark-fuzz ../test/cmark-fuzz.c ${LIBRARY_SOURCES}) - target_link_libraries(cmark-fuzz "${CMAKE_LIB_FUZZER_PATH}") + add_executable(${FUZZ} ../test/cmark-fuzz.c ${LIBRARY_SOURCES}) + target_link_libraries(${FUZZ} PRIVATE ${CMAKE_LIB_FUZZER_PATH}) # cmark is written in C but the libFuzzer runtime is written in C++ which # needs to link against the C++ runtime. - set_target_properties(cmark-fuzz PROPERTIES - LINKER_LANGUAGE CXX) + set_target_properties(${FUZZ} PROPERTIES LINKER_LANGUAGE CXX) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5c07fb7b2..32944c197 100755 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,11 +56,15 @@ IF (PYTHONINTERP_FOUND) endif() add_test(spectest_executable - ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py" "--no-normalize" "--spec" "${CMAKE_CURRENT_SOURCE_DIR}/spec.txt" "--program" "${CMAKE_CURRENT_BINARY_DIR}/../src/cmark" + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py" "--no-normalize" + "--spec" "${CMAKE_CURRENT_SOURCE_DIR}/spec.txt" + "--program" "${CMAKE_CURRENT_BINARY_DIR}/../src/cmark" ) add_test(smartpuncttest_executable - ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py" "--no-normalize" "--spec" "${CMAKE_CURRENT_SOURCE_DIR}/smart_punct.txt" "--program" "${CMAKE_CURRENT_BINARY_DIR}/../src/cmark --smart" + ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py" "--no-normalize" + "--spec" "${CMAKE_CURRENT_SOURCE_DIR}/smart_punct.txt" + "--program" "${CMAKE_CURRENT_BINARY_DIR}/../src/cmark --smart" ) add_test(regressiontest_executable @@ -70,11 +74,9 @@ IF (PYTHONINTERP_FOUND) "${CMAKE_CURRENT_BINARY_DIR}/../src/cmark" ) -ELSE(PYTHONINTERP_FOUND) - +else() message("\n*** A python 3 interpreter is required to run the spec tests.\n") add_test(skipping_spectests echo "Skipping spec tests, because no python 3 interpreter is available.") - -ENDIF(PYTHONINTERP_FOUND) +endif()