Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CMakeLists.txt 16.89 KiB
#
# This file is a part of the CaosDB Project.
#
# Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
# Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#

cmake_minimum_required(VERSION 3.13)

set(libcaosdb_VERSION 0.3.0)
set(libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR 0)
set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 9)
set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 0)
set(libcaosdb_COMPATIBLE_SERVER_VERSION_PRE_RELEASE "")

project(libcaosdb
    VERSION ${libcaosdb_VERSION}
    DESCRIPTION "C and C++ client libraries for CaosDB"
    LANGUAGES CXX C)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

IF (WIN32)
    set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
ENDIF()

IF (BUILD_ACM)
    message(STATUS "BUILD_ACM")
    add_compile_definitions("BUILD_ACM")
ENDIF()

###########################################
### DEPENDENCY MANAGEMENT with CONAN
###########################################
message(STATUS "Build directory ${CMAKE_BINARY_DIR}")

# TODO: Is this still necessary?
# # fix grpc - remove unsecure (no-op ssl implementations)
# string(REGEX REPLACE "grpc\\+?\\+?_unsecure" "" CONAN_LIBS_GRPC
#     "${CONAN_LIBS_GRPC}")
# string(REGEX REPLACE "grpc\\+?\\+?_unsecure" "" CONAN_PKG_LIBS_GRPC
#     "${CONAN_PKG_LIBS_GRPC}")
# string(REGEX REPLACE "grpc\\+?\\+?_unsecure" "" CONAN_LIBS
#     "${CONAN_LIBS}")
# string(REGEX REPLACE "grpc\\+?\\+?_unsecure" "" CONAN_PKG_LIBS
#     "${CONAN_PKG_LIBS}")

# message(STATUS "CONAN_LIBS: ${CONAN_LIBS}")

###########################################
### GENERAL SETUP of SOURCES
###########################################
set(PROJECT_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include")
add_subdirectory(src)
add_subdirectory(include)
add_subdirectory(doc)

####################################################################
### CODE GENERATION (WITH GRPC)
####################################################################

# TODO: Replace this with the protobuf_generate_cpp function

# Protobuf/Grpc source files
set(PROTO_FILES
    ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/info/v1/main.proto
    ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/entity/v1/main.proto
)

IF (BUILD_ACM)
    list(APPEND PROTO_FILES
         ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/acm/v1alpha1/main.proto
         )
ENDIF()

set(PROTO_PATH ${PROJECT_SOURCE_DIR}/proto/proto)

# compiler binaries
IF (WIN32)
    set(_PROTOBUF_PROTOC "${CMAKE_BINARY_DIR}/build_tools/protoc.exe")
    set(_GRPC_CPP_PLUGIN_EXECUTABLE "${CMAKE_BINARY_DIR}/build_tools/grpc_cpp_plugin.exe")
    set(STDFSLIB "")
ELSE()
    set(_PROTOBUF_PROTOC "${CMAKE_BINARY_DIR}/build_tools/protoc")
    set(_GRPC_CPP_PLUGIN_EXECUTABLE "${CMAKE_BINARY_DIR}/build_tools/grpc_cpp_plugin")
    set(STDFSLIB stdc++fs)
ENDIF()

# Generated sources
list(LENGTH PROTO_FILES len_proto_files)
math(EXPR len_proto_files "${len_proto_files} - 1")
foreach(i RANGE "${len_proto_files}")
    list(GET PROTO_FILES ${i} next_proto_file)

    # strip away the prefix path and the ".proto" suffix
    string(REPLACE
        "${PROJECT_SOURCE_DIR}/proto/proto/caosdb/"
        ""
        next_proto_module
        "${next_proto_file}")
    string(REPLACE
        ".proto"
        ""
        next_proto_module
        "${next_proto_module}")
    set(next_proto_src
        "${CMAKE_CURRENT_BINARY_DIR}/include/caosdb/${next_proto_module}.pb.cc")
    set(next_proto_hdr
        "${CMAKE_CURRENT_BINARY_DIR}/include/caosdb/${next_proto_module}.pb.h")
    set(next_grpc_src
        "${CMAKE_CURRENT_BINARY_DIR}/include/caosdb/${next_proto_module}.grpc.pb.cc")
    set(next_grpc_hdr
        "${CMAKE_CURRENT_BINARY_DIR}/include/caosdb/${next_proto_module}.grpc.pb.h")
    list(APPEND GRPC_GENERATED_HEADERS "${next_proto_hdr}" "${next_grpc_hdr}")
    list(APPEND GRPC_GENERATED_SOURCES "${next_proto_src}" "${next_grpc_src}")
endforeach()

set(GRPC_GENERATED
    ${GRPC_GENERATED_SOURCES}
    ${GRPC_GENERATED_HEADERS})
add_custom_command(
      OUTPUT ${GRPC_GENERATED}
      COMMAND ${_PROTOBUF_PROTOC}
      ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}/include"
        --cpp_out "${CMAKE_CURRENT_BINARY_DIR}/include"
        -I "${PROTO_PATH}"
        --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}"
        ${PROTO_FILES}
      DEPENDS ${PROTO_FILES})

# show generated files
message(DEBUG "GRPC_GENERATED: ${GRPC_GENERATED}")

###############################################################################
### Set up main targets
### * [caosdb_grpc] - only in Debug builds. Otherwise this library is compiled
###   into caosdb libraray
### * caosdb (links to caosdb_grpc) - The main library.
### * cxxcaosdbcli - A C++ test client.
### * ccaosdb - A C-Wrapper of the C++ caosdb library.
### * ccaosdbcli - A plain C test client.
###############################################################################

find_package(gRPC CONFIG REQUIRED)
find_package(Protobuf CONFIG REQUIRED)
find_package(Boost REQUIRED)
find_package(GTest REQUIRED)

# print include directories for debugging
message(DEBUG "CMAKE_INCLUDE_PATH: ${CMAKE_INCLUDE_PATH}")
message(DEBUG "PROTOBUF_INCLUDE_DIRS: ${PROTOBUF_INCLUDE_DIRS}")
message(DEBUG "gRPC_INCLUDE_DIRS: ${gRPC_INCLUDE_DIRS}")


# libcaosdb
# ---------

# In Debug, build separate libraries for grpc-generated code and caosdb
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")

    add_library(caosdb_grpc SHARED ${GRPC_GENERATED})
    target_link_libraries(caosdb_grpc 
        grpc::grpc protobuf::protobuf boost::boost
    )
    target_include_directories(caosdb_grpc PUBLIC
        $<BUILD_INTERFACE:${PROJECT_INCLUDE_DIR}>
        $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
        $<INSTALL_INTERFACE:include>
    )

   add_library(caosdb SHARED ${libcaosdb_INCL} ${libcaosdb_SRC})

   target_link_libraries(caosdb 
        caosdb_grpc grpc::grpc protobuf::protobuf boost::boost
    )

    set(LIBCAOSDB caosdb caosdb_grpc)
else()
    add_library(caosdb
        SHARED ${libcaosdb_INCL} ${libcaosdb_SRC} ${GRPC_GENERATED})
     target_link_libraries(caosdb
        grpc::grpc protobuf::protobuf boost::boost 
    )
     set(LIBCAOSDB caosdb)
endif()


target_include_directories(caosdb PUBLIC
    $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
    $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
    $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/src>
    $<INSTALL_INTERFACE:include>
)




# libccaosdb
# ----------
add_library(ccaosdb SHARED src/ccaosdb.cpp ${GRPC_GENERATED})
target_link_libraries(ccaosdb
    grpc::grpc protobuf::protobuf boost::boost
    ${LIBCAOSDB} 
)
target_include_directories(ccaosdb PUBLIC
    $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
    $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
    $<INSTALL_INTERFACE:include>
)


# ccaosdbcli
# ----------
add_executable(ccaosdbcli EXCLUDE_FROM_ALL src/ccaosdbcli.c)
target_include_directories(ccaosdbcli PUBLIC
    $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
    $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
    $<INSTALL_INTERFACE:include>
)
target_include_directories(ccaosdbcli SYSTEM PUBLIC
    ${CONAN_INCLUDE_DIRS}
)

target_link_libraries(ccaosdbcli
    grpc::grpc protobuf::protobuf boost::boost
    ${LIBCAOSDB}
    ccaosdb
)

# cxxcaosdbcli
# ------------
add_executable(cxxcaosdbcli EXCLUDE_FROM_ALL src/cxxcaosdbcli.cpp)
target_include_directories(cxxcaosdbcli PUBLIC
    $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
    $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
    $<INSTALL_INTERFACE:include>
)
target_include_directories(cxxcaosdbcli SYSTEM PUBLIC
    ${CONAN_INCLUDE_DIRS}
)
target_link_libraries(cxxcaosdbcli
    ${LIBCAOSDB}
    grpc::grpc protobuf::protobuf boost::boost
)



#######################################################
### LINTING with CLANG-TIDY and INCLUDE-WHAT-YOU-USE
#######################################################

include(CheckCXXCompilerFlag)
include(CheckCCompilerFlag)

function(add_compiler_flag flag)
    string(FIND "${CMAKE_CXX_FLAGS}" "${flag}" cxx_present)
    if(cxx_present EQUAL -1)
        check_cxx_compiler_flag("${flag}" flag_supported)
        if(flag_supported)
            set(PEDANTIC_CMAKE_CXX_FLAGS "${PEDANTIC_CMAKE_CXX_FLAGS} ${flag}" PARENT_SCOPE)
        endif()
        unset(flag_supported CACHE)
    endif()
    unset(cxx_present CACHE)

    string(FIND "${CMAKE_C_FLAGS}" "${flag}" c_present)
    if(c_present EQUAL -1)
        check_cxx_compiler_flag("${flag}" flag_supported)
        if(flag_supported)
            set(PEDANTIC_CMAKE_C_FLAGS "${PEDANTIC_CMAKE_C_FLAGS} ${flag}" PARENT_SCOPE)
        endif()
        unset(flag_supported CACHE)
    endif()
    unset(c_present CACHE)
endfunction()



option(LINTING "Enable linting with clang-tidy and iwyu when in non-Debug build-type" OFF)
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug" OR LINTING)
    set(_LINTING ON)
endif()
option(SKIP_LINTING "Skip linting even when in Debug build-type" OFF)
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug" AND SKIP_LINTING)
    message(WARNING "Skipping linting due to SKIP_LINTING option")
    set(_LINTING OFF)
endif()
if(_LINTING)

    ### set paranoid compiler flags
    add_compiler_flag("-Wall")
    add_compiler_flag("-Wextra")
    add_compiler_flag("-pedantic")
    # add_compiler_flag("-Werror") # removed until issue #71 is resolved

    message(STATUS "PEDANTIC_CMAKE_CXX_FLAGS: [${PEDANTIC_CMAKE_CXX_FLAGS}]")
    set(TARGET_CAOSDB_COMPILE_FLAGS "${TARGET_CAOSDB_COMPILE_FLAGS} ${PEDANTIC_CMAKE_CXX_FLAGS}")
    set(TARGET_CCAOSDB_COMPILE_FLAGS "${TARGET_CCAOSDB_COMPILE_FLAGS} ${PEDANTIC_CMAKE_C_FLAGS}")
    set(TARGET_CXXCAOSDBCLI_COMPILE_FLAGS "${TARGET_CXXCAOSDBCLI_COMPILE_FLAGS} ${PEDANTIC_CMAKE_CXX_FLAGS}")
    set(TARGET_CCAOSDBCLI_COMPILE_FLAGS "${TARGET_CCAOSDBCLI_COMPILE_FLAGS} ${PEDANTIC_CMAKE_C_FLAGS}")

    set_target_properties(caosdb PROPERTIES
        COMPILE_FLAGS "${TARGET_CAOSDB_COMPILE_FLAGS}")
    set_target_properties(ccaosdb PROPERTIES
        COMPILE_FLAGS "${TARGET_CCAOSDB_COMPILE_FLAGS}")
    set_target_properties(cxxcaosdbcli PROPERTIES
        COMPILE_FLAGS "${TARGET_CXXCAOSDBCLI_COMPILE_FLAGS}")
    set_target_properties(ccaosdbcli PROPERTIES
        COMPILE_FLAGS "${TARGET_CCAOSDBCLI_COMPILE_FLAGS}")

    find_program(iwyu
        NAMES include-what-you-use iwyu
        PATHS ${CMAKE_SOURCE_DIR}/tools/include-what-you-use/${iwyu_os}/bin)
    if(NOT iwyu)
        message(WARNING "include-what-you-use: Not found")
    else()
        message(STATUS "include-what-you-use: ${iwyu}")
        set(_CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${iwyu}
            "-Xiwyu" "--cxx17ns" "-Xiwyu" "--no_fwd_decls")

        set_target_properties(caosdb PROPERTIES
            CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
            )
        set_target_properties(cxxcaosdbcli PROPERTIES
            CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
            )
        set_target_properties(ccaosdbcli PROPERTIES
            C_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
            )
    endif()

    find_program(clang_tidy NAMES clang-tidy clang-tidy-11)
    if(NOT clang_tidy)
        message(WARNING "clang-tidy: Not found")
    else()
        message(STATUS "clang-tidy: ${clang_tidy}")
        set(_CMAKE_CXX_CLANG_TIDY_CHECKS
            "--checks=*,-fuchsia-*,-llvmlibc-*,-readability-convert-member-functions-to-static,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay,-llvm-else-after-return,-readability-else-after-return,-modernize-use-trailing-return-type,-bugprone-branch-clone,-altera-*,-misc-include-cleaner,-readability-identifier-*,-llvm-include-order,-misc-const-correctness")
        set(_CMAKE_C_CLANG_TIDY_CHECKS "${_CMAKE_CXX_CLANG_TIDY_CHECKS}")
        set(_CMAKE_CXX_CLANG_TIDY "${clang_tidy}"
            "--header-filter=caosdb/.*[^\(\.pb\.h\)]$")
            # "--warnings-as-errors=*")
        set(_CMAKE_C_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY}")
        option(AUTO_FIX_LINTING "Append --fix option to clang-tidy" OFF)
        if(AUTO_FIX_LINTING)
            set(_CMAKE_CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};--fix")
        endif()
        message(STATUS "Using clang-tidy with
            '${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}'")
        set_target_properties(caosdb PROPERTIES
            CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}"
            )
        set_target_properties(cxxcaosdbcli PROPERTIES
            CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}"
            )
        set_target_properties(ccaosdb PROPERTIES
            C_CLANG_TIDY "${_CMAKE_C_CLANG_TIDY};${_CMAKE_C_CLANG_TIDY_CHECKS}"
            )
        set_target_properties(ccaosdbcli PROPERTIES
            C_CLANG_TIDY "${_CMAKE_C_CLANG_TIDY};${_CMAKE_C_CLANG_TIDY_CHECKS}"
            )
    endif()
endif()


#######################################################
### UNIT TEST
#######################################################

if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
    enable_testing()
    add_subdirectory(test)
endif()

# ###############################################
# ############ INSTALLATION #####################
# ###############################################

set(libcaosdb_INCLUDE_DEST "include/caosdb")
set(libcaosdb_LIB_DEST "lib")

set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local/")
install(
    # targets to install
    TARGETS ${LIBCAOSDB} ccaosdb
    # name of the CMake "export group" containing the targets we want to install
    EXPORT caosdbTargets
    # Dynamic, static library and include destination locations after running
    # "make install"
    LIBRARY DESTINATION ${libcaosdb_LIB_DEST}
    ARCHIVE DESTINATION ${libcaosdb_LIB_DEST}
    INCLUDES DESTINATION ${libcaosdb_INCLUDE_DEST}
)


set(libcaosdb_CMAKE_DEST "${libcaosdb_LIB_DEST}/cmake/caosdb")
install(
    # The export we want to save (matches name defined above containing the
    # install targets)
    EXPORT caosdbTargets
    # CMake file in which to store the export's information
    FILE  caosdbTargets.cmake
    # Namespace prepends all targets in the export (when we import later, we
    # will use caosdb::caosdb)
    NAMESPACE caosdb::
    # where to place the resulting file (here, we're putting it with the library)
    DESTINATION ${libcaosdb_CMAKE_DEST}
)

install(FILES ${libcaosdb_INCL} ${PROJECT_SOURCE_DIR}/include/ccaosdb.h DESTINATION ${libcaosdb_INCLUDE_DEST})
foreach(i RANGE "${len_proto_files}")
    list(GET PROTO_FILES ${i} next_proto_file)

    # strip away the prefix path and the ".proto" suffix
    string(REPLACE
        "${PROJECT_SOURCE_DIR}/proto/proto/caosdb/"
        ""
        next_proto_module
        "${next_proto_file}")
    string(REPLACE
        "/main.proto"
        ""
        next_proto_module
        "${next_proto_module}")
    set(next_proto_hdr
        "${CMAKE_CURRENT_BINARY_DIR}/include/caosdb/${next_proto_module}/main.pb.h")
    set(next_grpc_hdr
        "${CMAKE_CURRENT_BINARY_DIR}/include/caosdb/${next_proto_module}/main.grpc.pb.h")
    install(FILES ${next_proto_hdr} ${next_grpc_hdr} DESTINATION
        ${libcaosdb_INCLUDE_DEST}/${next_proto_module})
endforeach()

install(FILES ${PROJECT_SOURCE_DIR}/caosdbConfig.cmake
    DESTINATION ${libcaosdb_CMAKE_DEST})

#set_property(TARGET caosdb PROPERTY VERSION ${libcaosdb_VERSION})
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    "${PROJECT_SOURCE_DIR}/caosdbConfigVersion.cmake"
  VERSION ${libcaosdb_VERSION}
  COMPATIBILITY AnyNewerVersion
)
install(FILES ${PROJECT_SOURCE_DIR}/caosdbConfigVersion.cmake
    DESTINATION ${libcaosdb_CMAKE_DEST})

#######################################################
### code formatting with clang-format
#######################################################
option(AUTOFORMATTING "call clang-format at configure time" ON)
if(AUTOFORMATTING AND NOT SKIP_LINTING)
    find_program(clang_format NAMES clang-format-11 clang-format)
    file(GLOB format_test_sources test/*.cpp test/*.h test/*.h.in)
    execute_process(COMMAND ${clang_format} -i --verbose ${libcaosdb_INCL}
        ${libcaosdb_SRC} ${libcaosdb_TEST_SRC}
        ${PROJECT_SOURCE_DIR}/src/cxxcaosdbcli.cpp
        ${PROJECT_SOURCE_DIR}/src/ccaosdbcli.c
        ${PROJECT_SOURCE_DIR}/src/ccaosdb.cpp
        ${PROJECT_SOURCE_DIR}/include/ccaosdb.h
        ${format_test_sources}
        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
endif()