CMake question: Two same output obj generated by VS IDE and CMake command line cause LNK4006 - cmake

I am new for CMake, and I'm adding NASM files into projects by CMakelists.
With this version, IDE and project have two output folders to generate same obj, so that cause warning lnk4006 already defined second definition ignored.
One output folder and it is like build\encoder\x86.
Another is like build\encoder\x86\xxxenc_x86_asm.dir\Debug\ or build\encoder\x86\xxxenc_x86_asm.dir\Release.
I have trid to update the second output path to be same with the first, but it can't work.
CMakelists like following:
add_library(${ENCODER_X86_ASM_LIB_NAME} OBJECT "")
if ((LINUX OR MACOSX OR WIN32) AND ${ENABLE_ASM})
set(ASM_EXECUTABLE "${NASM_EXE}")
if(CMAKE_GENERATOR STREQUAL "Xcode")
add_library(${ENCODER_NATIVE_ASM_LIB_NAME} INTERFACE)
endif()
set(X86_ASM_SRCS
asm/avx2/average_avx2.asm)
if (WIN32)
set(ASM_FLAGS ...)
elseif(MACOSX)
set(ASM_FLAGS -I${PROJECT_SOURCE_DIR}/ -f macho64 -O2 -DARCH_X86_64=1 -DPREFIX -DOS_MAC=1 -DPIC -Worphan-labels -DSTACK_ALIGNMENT=16)
elseif(LINUX)
set(ASM_FLAGS -I${PROJECT_SOURCE_DIR}/ -f elf64 -O2 -DARCH_X86_64=1 -DOS_MAC=0 -DPIC -Worphan-labels -DSTACK_ALIGNMENT=16)
endif()
#generate objects when building CMake
if(CMAKE_GENERATOR STREQUAL "Xcode")
asm_compile_to_target(${ENCODER_NATIVE_ASM_LIB_NAME} ${X86_ASM_SRCS})
else()
asm_compile_to_target(${ENCODER_X86_ASM_LIB_NAME} ${X86_ASM_SRCS})
endif()
if ((MACOSX AND (CMAKE_GENERATOR STREQUAL "Xcode")) OR WIN32)
foreach(asm_file ${X86_ASM_SRCS})
set(ASM_SRC ${CMAKE_CURRENT_LIST_DIR}/${asm_file})
get_filename_component(filename "${asm_file}" NAME_WE)
set(ASM_OBJ "${CMAKE_CURRENT_BINARY_DIR}/${filename}${CMAKE_C_OUTPUT_EXTENSION}")
list(APPEND ASM_SRCS ${ASM_SRC})
list(APPEND ASM_OBJS ${ASM_OBJ})
add_custom_command(
OUTPUT ${ASM_OBJ}
COMMAND ${ASM_EXECUTABLE}
ARGS ${ASM_FLAGS} ${ASM_SRC} -o ${ASM_OBJ}
DEPENDS ${ASM_SRC}
)
endforeach()
foreach(OBJ ${ASM_OBJS})
list(APPEND ASM_PRIMITIVES ${OBJ})
endforeach()
foreach(SRC ${X86_ASM_SRCS})
list(APPEND ASM_PRIMITIVES ${CMAKE_CURRENT_LIST_DIR}/${SRC})
endforeach()
source_group(Assembly FILES ${ASM_PRIMITIVES})
if(CMAKE_GENERATOR STREQUAL "Xcode")
target_sources(${ENCODER_NATIVE_ASM_LIB_NAME} INTERFACE ${ASM_PRIMITIVES})
else()
target_sources(${ENCODER_X86_ASM_LIB_NAME} PRIVATE ${ASM_PRIMITIVES})
endif()
if (MACOSX)
add_custom_target(${ENCODER_X86_ASM_LIB_NAME}-asm ALL DEPENDS ${ASM_PRIMITIVES})
target_sources(${ENCODER_X86_ASM_LIB_NAME} INTERFACE ${ASM_PRIMITIVES})
add_dependencies(${ENCODER_X86_ASM_LIB_NAME} ${ENCODER_X86_ASM_LIB_NAME}-asm)
else()
target_sources(${ENCODER_X86_ASM_LIB_NAME} PRIVATE ${ASM_PRIMITIVES})
endif()
endif() ## if ((MACOSX) AND (CMAKE_GENERATOR STREQUAL "Xcode") OR WIN32)
endif() ## if ((LINUX OR MACOSX OR WIN32) AND ${ENABLE_AVX2})
target_compile_definitions(${ENCODER_X86_ASM_LIB_NAME} PUBLIC)
Here, CMAKE_CURRENT_BINARY_DIR is one output folder and it is build\encoder\x86.
how to deal with this issue?
Background is this: we need to support incremental compiling in IDE, also need to support building by cmake command line.
I have tried to update output path(or directory) as:
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES LIBRARY_OUTPUT_PATH ${PATH} )
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES BUILD_RPATH ${PATH} )
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES INSTALL_RPATH ${PATH} )
set_target_properties(${ENCODER_X86_ASM_LIB_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PATH} )
It just can't work.
Thanks!

Related

add_custom_target does not appear to properly expand variable in cmake

I'm trying to integrate clang-tidy and am attempting to dynamically establish the include directories. My cmake looks like:
if(UNIX)
file(GLOB_RECURSE ALL_CXX_SOURCE_FILES *.cpp *.hpp)
file(GLOB_RECURSE ALL_HEADERS *.hpp)
set(ALL_INCLUDE_DIRECTORIES "")
foreach (_headerFile ${ALL_HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
if(ALL_INCLUDE_DIRECTORIES STREQUAL "")
set(ALL_INCLUDE_DIRECTORIES "-I${_dir}")
else()
set(ALL_INCLUDE_DIRECTORIES "-I${_dir} ${ALL_INCLUDE_DIRECTORIES}")
endif()
endforeach()
message(${ALL_INCLUDE_DIRECTORIES})
add_custom_target(clang-tidy COMMAND /usr/bin/clang-tidy ${ALL_CXX_SOURCE_FILES} -checks=* -- -std=c++11 ${ALL_INCLUDE_DIRECTORIES})
endif()
The ${ALL_INCLUDE_DIRECTORIES} does not appear to expand correctly in the add_custom_target because the 'make clang-tidy' reports errors for not finding the headers at the include paths. However, if I use the output from message(${ALL_INCLUDE_DIRECTORIES}) to replace the ${ALL_INCLUDE_DIRECTORIES} in the add_custom_target I do not get these errors and clang-tidy appears to find the headers.
This works. Use a list:
if(UNIX)
file(GLOB_RECURSE ALL_CXX_SOURCE_FILES *.cpp *.hpp)
file(GLOB_RECURSE ALL_HEADERS *.hpp)
set(ALL_INCLUDE_DIRECTORIES "")
foreach (_headerFile ${ALL_HEADERS})
get_filename_component(_dir ${_headerFile} PATH)
list(APPEND ALL_INCLUDE_DIRECTORIES -I${_dir})
endforeach()
add_custom_target(clang-tidy COMMAND /usr/bin/clang-tidy ${ALL_CXX_SOURCE_FILES} -checks=* -- -std=c++11 ${ALL_INCLUDE_DIRECTORIES})
endif()

Detect Sun Studio compiler and add platform libraries in CMakeList.txt?

Sun Studio 12.5 on Solaris 11.3. Solve one problem and move to the next... Building our project with CMake results the link error below.
I believe its a simple matter of detecting SunCC and adding -lnsl -lsocket to LDLIBS. However, the method to detect the SunCC compiler escapes me. I found an old post from 2006 that states (from Error detecting sun studio compiler under linux):
I am trying to use the sun studio compiler under linux and I am having a
terrible time getting past the cmake compiler tests.
AFAIK no one has tried CMake with this compiler before.... CMake is invoking the compiler assuming that it accepts the flags other Linux compilers (such as GNU and Intel) accept... You'll have to setup a platform file to configure this compiler.
I tried to use SunPro from CMake Compiler IDs, but it results in the same error shown below.
if(SunPro)
target_link_libraries(cryptopp-shared nsl socket)
target_link_libraries(cryptest nsl socket)
endif()
My question is, how do I detect the Sun Studio compiler in CMakeList.txt? Or how do I detect Solaris?
/opt/developerstudio12.5/bin/CC -DNDEBUG -g2 -O2 -D__SSE2__ -D__SSE3__ -D__SSSE3__
-D__SSE4_1__ -D__SSE4_2__ -D__AES__ -D__PCLMUL__ -D__RDRND__ -D__RDSEED__ -D__AVX__
-D__AVX2__ -D__BMI__ -D__BMI2__ -D__ADX__ -xarch=avx2_i
CMakeFiles/cryptest.dir/bench1.cpp.o CMakeFiles/cryptest.dir/bench2.cpp.o
CMakeFiles/cryptest.dir/test.cpp.o CMakeFiles/cryptest.dir/validat1.cpp.o
CMakeFiles/cryptest.dir/validat2.cpp.o CMakeFiles/cryptest.dir/validat3.cpp.o
CMakeFiles/cryptest.dir/datatest.cpp.o CMakeFiles/cryptest.dir/regtest.cpp.o
CMakeFiles/cryptest.dir/fipsalgt.cpp.o CMakeFiles/cryptest.dir/dlltest.cpp.o
CMakeFiles/cryptest.dir/fipstest.cpp.o -o cryptest.exe libcryptopp.a
Undefined first referenced
symbol in file
bind libcryptopp.a(socketft.cpp.o)
recv libcryptopp.a(socketft.cpp.o)
send libcryptopp.a(socketft.cpp.o)
getservbyname libcryptopp.a(socketft.cpp.o)
getsockname libcryptopp.a(socketft.cpp.o)
accept libcryptopp.a(socketft.cpp.o)
listen libcryptopp.a(socketft.cpp.o)
gethostbyname libcryptopp.a(socketft.cpp.o)
socket libcryptopp.a(socketft.cpp.o)
setsockopt CMakeFiles/cryptest.dir/test.cpp.o
connect libcryptopp.a(socketft.cpp.o)
getpeername libcryptopp.a(socketft.cpp.o)
inet_addr libcryptopp.a(socketft.cpp.o)
shutdown libcryptopp.a(socketft.cpp.o)
ld: fatal: symbol referencing errors
gmake[2]: *** [cryptest.exe] Error 2
gmake[2]: Leaving directory `/export/home/cryptopp-build'
gmake[1]: *** [CMakeFiles/cryptest.dir/all] Error 2
gmake[1]: Leaving directory `/export/home/cryptopp-build'
gmake: *** [all] Error 2
Here's the CMakeList.tx file. It has not been checked in yet, so I have to dump it here:
$ cat CMakeLists.txt
# Please ensure your changes or patch meets minimum requirements.
# The minimum requirements are below, and they are 2.8.5. Please
# do not check in something for 2.8.12. To test your changes,
# please set up a Ubuntu 12.04 LTS system. Then, manually install
# CMake 2.8.5 from http://cmake.org/Wiki/CMake_Released_Versions.
cmake_minimum_required(VERSION 2.8.5 FATAL_ERROR)
project(cryptopp)
set(cryptopp_VERSION_MAJOR 5)
set(cryptopp_VERSION_MINOR 6)
set(cryptopp_VERSION_PATCH 5)
include(GNUInstallDirs)
include(TestBigEndian)
#============================================================================
# Settable options
#============================================================================
option(BUILD_STATIC "Build static library" ON)
option(BUILD_SHARED "Build shared library" ON)
option(BUILD_TESTING "Build library tests" ON)
option(BUILD_DOCUMENTATION "Use Doxygen to create the HTML based API documentation" OFF)
option(DISABLE_ASM "Disable ASM" OFF)
option(DISABLE_SSSE3 "Disable SSSE3" OFF)
option(DISABLE_AESNI "Disable AES-NI" OFF)
set(CRYPTOPP_DATA_DIR "" CACHE PATH "Crypto++ test data directory")
#============================================================================
# Internal compiler options
#============================================================================
# Don't use RPATH's. The resulting binary could fail a security audit.
if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
set(CMAKE_MACOSX_RPATH 0)
endif()
set(LIB_VER ${cryptopp_VERSION_MAJOR}${cryptopp_VERSION_MINOR}${cryptopp_VERSION_PATCH})
if(CMAKE_CXX_COMPILER_ID MATCHES "Intel")
add_definitions(-wd68 -wd186 -wd279 -wd327 -wd161 -wd3180)
endif()
# Endianess
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
add_definitions(-DIS_BIG_ENDIAN)
endif()
if(DISABLE_ASM)
add_definitions(-DCRYPTOPP_DISABLE_ASM)
endif()
if(DISABLE_SSSE3)
add_definitions(-DCRYPTOPP_DISABLE_SSSE3)
endif()
if(DISABLE_AESNI)
add_definitions(-DCRYPTOPP_DISABLE_AESNI)
endif()
if(NOT CRYPTOPP_DATA_DIR STREQUAL "")
add_definitions(-DCRYPTOPP_DATA_DIR="${CRYPTOPP_DATA_DIR}")
endif()
if(WINDOWS_STORE OR WINDOWS_PHONE)
if("${CMAKE_SYSTEM_VERSION}" MATCHES "10\\.0.*")
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D\"_WIN32_WINNT=0x0A00\"" )
endif()
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /FI\"winapifamily.h\"" )
endif()
#============================================================================
# Sources & headers
#============================================================================
# Library headers
file(GLOB cryptopp_HEADERS *.h)
# Test sources. You can use the GNUmakefile to generate the list: `make sources`.
file(GLOB cryptopp_SOURCES_TEST bench1.cpp bench2.cpp test.cpp validat1.cpp validat2.cpp validat3.cpp adhoc.cpp datatest.cpp regtest.cpp fipsalgt.cpp dlltest.cpp fipstest.cpp)
# Library sources. You can use the GNUmakefile to generate the list: `make sources`.
file(GLOB cryptopp_SOURCES *.cpp)
list(REMOVE_ITEM cryptopp_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/cryptlib.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cpu.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pch.cpp
${CMAKE_CURRENT_SOURCE_DIR}/simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/winpipes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cryptlib_bds.cpp
${cryptopp_SOURCES_TEST}
)
set(cryptopp_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/cryptlib.cpp
${CMAKE_CURRENT_SOURCE_DIR}/cpu.cpp
${cryptopp_SOURCES}
)
if(MINGW OR WIN32)
list(APPEND cryptopp_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/winpipes.cpp)
endif()
if(MSVC AND NOT DISABLE_ASM)
if(${CMAKE_GENERATOR} MATCHES ".*ARM")
message(STATUS "Disabling ASM because ARM is specified as target platform.")
else()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND cryptopp_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/x64dll.asm)
list(APPEND cryptopp_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/x64masm.asm)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/x64dll.asm PROPERTIES COMPILE_FLAGS "/D_M_X64")
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/x64masm.asm PROPERTIES COMPILE_FLAGS "/D_M_X64")
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/rdrand.asm PROPERTIES COMPILE_FLAGS "/D_M_X64")
else()
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/x64dll.asm PROPERTIES COMPILE_FLAGS "/D_M_X86 /safeseh")
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/x64masm.asm PROPERTIES COMPILE_FLAGS "/D_M_X86 /safeseh")
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/rdrand.asm PROPERTIES COMPILE_FLAGS "/D_M_X86 /safeseh")
endif()
list(APPEND cryptopp_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/rdrand.asm)
enable_language(ASM_MASM)
endif()
endif()
#============================================================================
# Compile targets
#============================================================================
# Set global includes BEFORE adding any targets for legacy CMake versions
if(CMAKE_VERSION VERSION_LESS 2.8.12)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
endif()
if(NOT CMAKE_VERSION VERSION_LESS 2.8.8)
add_library(cryptopp-object OBJECT ${cryptopp_SOURCES})
endif()
if (BUILD_STATIC)
if(NOT CMAKE_VERSION VERSION_LESS 2.8.8)
add_library(cryptopp-static STATIC $<TARGET_OBJECTS:cryptopp-object>)
else()
add_library(cryptopp-static STATIC ${cryptopp_SOURCES})
endif()
if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
target_include_directories(cryptopp-static PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:include/cryptopp>)
endif()
endif()
if (BUILD_SHARED)
if(NOT CMAKE_VERSION VERSION_LESS 2.8.8)
add_library(cryptopp-shared SHARED $<TARGET_OBJECTS:cryptopp-object>)
else()
add_library(cryptopp-shared SHARED ${cryptopp_SOURCES})
endif()
if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
target_include_directories(cryptopp-shared PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:include/cryptopp>)
endif()
endif()
# Set PIC
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# Enables -fPIC on all 64-bit platforms
if(NOT CMAKE_VERSION VERSION_LESS 2.8.9) # POSITION_INDEPENDENT_CODE support
set_target_properties(cryptopp-object PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
elseif(NOT CMAKE_VERSION VERSION_LESS 2.8.8) # Object library support
get_target_property(flags_old cryptopp-object COMPILE_FLAGS)
set_target_properties(cryptopp-object PROPERTIES COMPILE_FLAGS "${flags_old} -fPIC")
else()
if (BUILD_STATIC)
get_target_property(flags_old_static cryptopp-static COMPILE_FLAGS)
if(NOT flags_old_static)
set(flags_old_static "")
endif()
set_target_properties(cryptopp-static PROPERTIES COMPILE_FLAGS "${flags_old_static} -fPIC")
endif()
if (BUILD_SHARED)
get_target_property(flags_old_shared cryptopp-shared COMPILE_FLAGS)
if(NOT flags_old_shared)
set(flags_old_shared "")
endif()
set_target_properties(cryptopp-shared PROPERTIES COMPILE_FLAGS "${flags_old_shared} -fPIC")
endif()
endif()
endif()
# Set filenames for targets to be "cryptopp"
if(NOT MSVC)
set(COMPAT_VERSION ${cryptopp_VERSION_MAJOR}.${cryptopp_VERSION_MINOR})
if (BUILD_STATIC)
set_target_properties(cryptopp-static
PROPERTIES
OUTPUT_NAME cryptopp)
endif()
if (BUILD_SHARED)
set_target_properties(cryptopp-shared
PROPERTIES
SOVERSION ${COMPAT_VERSION}
OUTPUT_NAME cryptopp)
endif()
endif()
# Targets, compatible with Crypto++ GNUMakefile
if (BUILD_STATIC)
add_custom_target(static)
add_dependencies(static cryptopp-static)
endif()
if (BUILD_SHARED)
add_custom_target(dynamic)
add_dependencies(dynamic cryptopp-shared)
endif()
#============================================================================
# Third-party libraries
#============================================================================
if(WIN32)
if (BUILD_STATIC)
target_link_libraries(cryptopp-static ws2_32)
endif()
if (BUILD_SHARED)
target_link_libraries(cryptopp-shared ws2_32)
endif()
endif()
if(SunPro)
target_link_libraries(cryptopp-shared nsl socket)
target_link_libraries(cryptest nsl socket)
endif()
find_package(Threads)
if (BUILD_STATIC)
target_link_libraries(cryptopp-static ${CMAKE_THREAD_LIBS_INIT})
endif()
if (BUILD_SHARED)
target_link_libraries(cryptopp-shared ${CMAKE_THREAD_LIBS_INIT})
endif()
#============================================================================
# Tests
#============================================================================
enable_testing()
if(BUILD_TESTING)
add_executable(cryptest ${cryptopp_SOURCES_TEST})
target_link_libraries(cryptest cryptopp-static)
# Setting "cryptest" binary name to "cryptest.exe"
if(NOT WIN32)
set_target_properties(cryptest PROPERTIES OUTPUT_NAME cryptest.exe)
endif()
if(NOT TARGET cryptest.exe)
add_custom_target(cryptest.exe)
add_dependencies(cryptest.exe cryptest)
endif()
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/TestData DESTINATION ${PROJECT_BINARY_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/TestVectors DESTINATION ${PROJECT_BINARY_DIR})
add_test(NAME build_cryptest COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target cryptest)
add_test(NAME cryptest COMMAND $<TARGET_FILE:cryptest> v)
set_tests_properties(cryptest PROPERTIES DEPENDS build_cryptest)
endif()
#============================================================================
# Doxygen documentation
#============================================================================
if(BUILD_DOCUMENTATION)
find_package(Doxygen REQUIRED)
set(in_source_DOCS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/html-docs")
set(out_source_DOCS_DIR "${PROJECT_BINARY_DIR}/html-docs")
add_custom_target(docs ALL
COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile -d CRYPTOPP_DOXYGEN_PROCESSING
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile
)
if(NOT ${in_source_DOCS_DIR} STREQUAL ${out_source_DOCS_DIR})
add_custom_command(
TARGET docs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${in_source_DOCS_DIR}" "${out_source_DOCS_DIR}"
COMMAND ${CMAKE_COMMAND} -E remove_directory "${in_source_DOCS_DIR}"
)
endif()
endif()
#============================================================================
# Install
#============================================================================
set(export_name "cryptopp-targets")
# Runtime package
if (BUILD_SHARED)
install(
TARGETS cryptopp-shared
EXPORT ${export_name}
DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endif()
# Development package
if (BUILD_STATIC)
install(TARGETS cryptopp-static EXPORT ${export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
install(FILES ${cryptopp_HEADERS} DESTINATION include/cryptopp)
# CMake Package
if(NOT CMAKE_VERSION VERSION_LESS 2.8.8) # CMakePackageConfigHelpers is supported from 2.8.8
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${PROJECT_BINARY_DIR}/cryptopp-config-version.cmake" VERSION ${cryptopp_VERSION_MAJOR}.${cryptopp_VERSION_MINOR}.${cryptopp_VERSION_PATCH} COMPATIBILITY SameMajorVersion)
install(FILES cryptopp-config.cmake ${PROJECT_BINARY_DIR}/cryptopp-config-version.cmake DESTINATION "lib/cmake/cryptopp")
install(EXPORT ${export_name} DESTINATION "lib/cmake/cryptopp")
endif()
# Tests
if(BUILD_TESTING)
install(TARGETS cryptest DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/TestData DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cryptopp)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/TestVectors DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/cryptopp)
endif()
# Documentation
if(BUILD_DOCUMENTATION)
install(DIRECTORY "${out_source_DOCS_DIR}" DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()

Using cmake to create protobuf / grpc cc files

If I want to recreate the following protoc command in cmake:
protoc -I ../proto/ --cpp_out=. service.proto
I use the following lines in cmake:
file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
If I instead want to recreate the protoc command below:
protoc -I ../proto/ --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` service.proto
In the case above I am not able to determine how to change the cmake file, please help!
The Question is how do I address the:
--plugin=EXECUTABLE Specifies a plugin executable to use.
Normally, protoc searches the PATH for
plugins, but you may specify additional
executables not in the path using this flag.
Additionally, EXECUTABLE may be of the form
NAME=PATH, in which case the given plugin name
is mapped to the given executable even if
the executable's own name differs.
I have been reading the PROTOBUF_GENERATE_CPP documentation, but did not find an answer!
Module findProtobuf.cmake defines functions-wrappers only for common protoc calls: PROTOBUF_GENERATE_CPP - for --cpp_out and PROTOBUF_GENERATE_PYTHON - for --py_out. But you can implement your own function-wrapper for needed plugin. Code below is based on PROTOBUF_GENERATE_CPP implementation.
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) # Get full path to plugin
function(PROTOBUF_GENERATE_GRPC_CPP SRCS HDRS)
if(NOT ARGN)
message(SEND_ERROR "Error: PROTOBUF_GENERATE_GRPC_CPP() called without any proto files")
return()
endif()
if(PROTOBUF_GENERATE_CPP_APPEND_PATH) # This variable is common for all types of output.
# Create an include path for each file specified
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(ABS_PATH ${ABS_FIL} PATH)
list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
if(${_contains_already} EQUAL -1)
list(APPEND _protobuf_include_path -I ${ABS_PATH})
endif()
endforeach()
else()
set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
endif()
if(DEFINED PROTOBUF_IMPORT_DIRS)
foreach(DIR ${Protobuf_IMPORT_DIRS})
get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
if(${_contains_already} EQUAL -1)
list(APPEND _protobuf_include_path -I ${ABS_PATH})
endif()
endforeach()
endif()
set(${SRCS})
set(${HDRS})
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc")
list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h")
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h"
COMMAND ${Protobuf_PROTOC_EXECUTABLE}
ARGS --grpc_out=${CMAKE_CURRENT_BINARY_DIR}
--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${_protobuf_include_path} ${ABS_FIL}
DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE}
COMMENT "Running gRPC C++ protocol buffer compiler on ${FIL}"
VERBATIM)
endforeach()
set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
set(${SRCS} ${${SRCS}} PARENT_SCOPE)
set(${HDRS} ${${HDRS}} PARENT_SCOPE)
endfunction()
Usage is same as for PROTOBUF_GENERATE_CPP:
file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
PROTOBUF_GENERATE_GRPC_CPP(ProtoGRPCSources ProtoGRPCHeaders ${ProtoFiles})
Starting at version 3.12, protobuf_generate supports a PLUGIN argument
https://github.com/protocolbuffers/protobuf/blob/v3.12.0/cmake/protobuf-config.cmake.in#L46
so you could try something along the line:
PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles} PLUGIN protoc-gen-grpc=${GRPC_CPP_PLUGIN_PATH})
For me the blogpost https://www.falkoaxmann.de/dev/2020/11/08/grpc-plugin-cmake-support.html lead to success because it provides a full example (thanks #powerpete).
I'm putting the code here so it is available as an answer and not just as a comment:
project(my-service VERSION 1.0 LANGUAGES CXX C)
find_package(protobuf CONFIG REQUIRED)
find_package(gRPC CONFIG REQUIRED)
find_package(Threads)
set(PROTO_FILES
MyService.proto
)
# protobuf source files go into the lib just like any other CPP source file
add_library(my-service ${PROTO_FILES})
target_link_libraries(my-service
PUBLIC
protobuf::libprotobuf
gRPC::grpc
gRPC::grpc++
)
target_include_directories(my-service
PUBLIC
${CMAKE_CURRENT_BINARY_DIR}
)
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
# compile the message types
protobuf_generate(TARGET my-service LANGUAGE cpp)
# compile the GRPC services
protobuf_generate(
TARGET
my-service
LANGUAGE
grpc
GENERATE_EXTENSIONS
.grpc.pb.h
.grpc.pb.cc
PLUGIN
"protoc-gen-grpc=${grpc_cpp_plugin_location}"
)

PROTOBUF_GENERATE_CPP not generating src and header files

My cmake configuration is not generating any protobuf src and header files.
I've already checked if the proto files can be found.
Cmakelists.txt
cmake_minimum_required(VERSION 3.0.2)
..
include(FindProtobuf REQUIRED)
file(GLOB PROTO_DEF "${CMAKE_CURRENT_SOURCE_DIR}/protobuf/*/*.proto")
foreach(file ${PROTO_DEF})
if(EXISTS ${file})
MESSAGE("YES")
else()
MESSAGE("NO")
endif()
endforeach()
SET(PROTOBUF_GENERATE_CPP_APPEND_PATH PROTOBUF)
SET(PROTOBUF_PROTOC_EXECUTABLE protoc.exe)
..
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_INCL ${PROTO_DEF})
..
add_library(${PROJECT_NAME} STATIC ${INCLUDES} ${INTERNAL_INCLUDES} ${SRC} ${PROTO_SRC} ${PROTO_INCL})
target_link_libraries(${PROJECT_NAME} ${PROTOBUF_LIBRARIES})
I have checked the FindProtobuf.cmake and half way through:
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc")
list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h")
MESSAGE(1 ${CMAKE_CURRENT_BINARY_DIR})
MESSAGE(2 ${_protobuf_include_path})
MESSAGE(3 ${ABS_FIL})
MESSAGE(4 ${PROTOBUF_PROTOC_EXECUTABLE})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
DEPENDS ${ABS_FIL}
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
VERBATIM )
endforeach()
You can see i've added the 4 message commands, the script reaches this point and variables show good values.
The proto files do have a depencency to the library, thus the command should get executed !?
Any ideas on this problem?
update
replacing the add_custom_command with
EXEC_PROGRAM(${PROTOBUF_PROTOC_EXECUTABLE} ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR} ${_protobuf_include_path} ${ABS_FIL}
does generate the source and header files, must i manually activate the custom_commmands?
Regards Auke
The add_custom_command is fired (for my project) during compilation time.
Adding
SET_SOURCE_FILES_PROPERTIES(${PROTO_SRC} ${PROTO_INCL} PROPERTIES GENERATED TRUE)
gives cmake info that the files will be generated.
Alternative if you have an external proto folder:
file(GLOB PROTOBUF_FILELIST ${PROTO_INCLUDE_DIR}/*.proto)
foreach( proto_file ${PROTOBUF_FILELIST} )
get_filename_component(proto_name ${proto_file} NAME_WE)
get_filename_component(proto_path ${PROTO_INCLUDE_DIR} ABSOLUTE)
set_source_files_properties("${proto_path}/${proto_name}.pb.cc"
"${proto_path}/${proto_name}.pb.h"
PROPERTIES GENERATED TRUE)
endforeach()
See that:
https://cmake.org/cmake/help/v3.20/module/FindProtobuf.html
Example:
find_package(Protobuf REQUIRED)
include_directories(${Protobuf_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS EXPORT_MACRO DLL_EXPORT foo.proto)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS DESCRIPTORS PROTO_DESCS foo.proto)
protobuf_generate_python(PROTO_PY foo.proto)
add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(bar ${Protobuf_LIBRARIES})
Note The protobuf_generate_cpp and protobuf_generate_python functions and add_executable() or add_library() calls only work properly within the same directory.
This problem only happens when the target is a library (using add_library, add_executable seems to be fine). The PROTOBUF_GENERATE_CPP will defer the generation of protobuf sources and headers when building the library. A workaround is to define a custom target and add it as a dependency to the lib target. e.g.
add_custom_target(proto_dep DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
add_library(${PROJECT_NAME} STATIC ${OTHER_SRCS})
add_dependencies(${PROJECT_NAME} proto_dep)
target_link_libraries(${PROJECT_NAME} PRIVATE gRPC::grpc++ gRPC::grpc++_reflection protobuf::libprotobuf)

How to automatically move *.pb.h and *.pb.h under /include and /src directories?

I am developing a library which uses Google Protocol Buffers (protobuf) and CMake. The project has the following directory tree.
MyProject/
MyProject/include/myproject/
MyProject/include/myproject/some_classes.h
MyProject/src/
MyProject/src/some_classes.cc
MyProject/src/foo.proto
MyProject/CMakeList.txt
CMakeList.txt has the following lines to generate protobuf source and header files.
include_directories(${libCHEC_SOURCE_DIR}/include)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCES)
find_package(Protobuf REQUIRED)
file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/src/*.proto")
protobuf_generate_cpp(ProtoSources ProtoHeaders ${ProtoFiles})
list(APPEND EXTLIBS ${PROTOBUF_LIBRARIES})
add_library(MyLibrary SHARED ${SOURCES} ${ProtoSources})
target_link_libraries(MyLibrary ${EXTLIBS})
When I execute cmake, foo.pb.h and foo.pb.cc are generated under the build directory (i.e. the directory where I executed cmake). It looks that this is the default behavior. But I would like to put foo.pb.h and foo.pb.cc under include/myproject and src directories, respectively.
How can I change the locations of the files generated by protoc?
I would strictly advise against placing generated files in the source tree.
CMake puts a lot of effort into separating the build and source trees. Forcing it to give up that separation has several disadvantages. Among the most prominent is the fact that version control will then have to deal with unversioned generated files in the source tree, and furthermore it may no longer be possible to have multiple builds targetting different architectures sharing the same source tree.
A better approach is to keep the files in the binary tree and adjust your target_include_directories accordingly. There is no shame in using generated files from the binary tree as sources, so don't hesitate to do it.
I added MyProject/misc/myprotobuf.cmake which had a modified version of PROTOBUF_GENERAGE_CPP.
function(MY_PROTOBUF_GENERATE_CPP PATH SRCS HDRS)
if(NOT ARGN)
message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
return()
endif()
if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
# Create an include path for each file specified
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(ABS_PATH ${ABS_FIL} PATH)
list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
if(${_contains_already} EQUAL -1)
list(APPEND _protobuf_include_path -I ${ABS_PATH})
endif()
endforeach()
else()
set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
endif()
if(DEFINED PROTOBUF_IMPORT_DIRS)
foreach(DIR ${PROTOBUF_IMPORT_DIRS})
get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
if(${_contains_already} EQUAL -1)
list(APPEND _protobuf_include_path -I ${ABS_PATH})
endif()
endforeach()
endif()
set(${SRCS})
set(${HDRS})
foreach(FIL ${ARGN})
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
get_filename_component(FIL_WE ${FIL} NAME_WE)
list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${PATH}/${FIL_WE}.pb.cc")
list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${PATH}/${FIL_WE}.pb.h")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${PATH})
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PATH}/${FIL_WE}.pb.cc"
"${CMAKE_CURRENT_BINARY_DIR}/${PATH}/${FIL_WE}.pb.h"
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR}/${PATH} ${_protobuf_include_path} ${ABS_FIL}
DEPENDS ${ABS_FIL}
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
VERBATIM )
endforeach()
set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
set(${SRCS} ${${SRCS}} PARENT_SCOPE)
set(${HDRS} ${${HDRS}} PARENT_SCOPE)
endfunction()
MyProject/CMakeLists.txt has the following two lines now.
include(${CMAKE_CURRENT_SOURCE_DIR}/misc/myprotobuf.cmake)
file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/misc/*.proto")
my_protobuf_generate_cpp(generated_files/myproject ProtoSources ProtoHeaders ${ProtoFiles})
include_directories(${CMAKE_CURRENT_BINARY_DIR}/generated_files)
You can manipulate the directory structure for your generated protobuf sources by modifying the source directory and cmakelists in a particular way.
An example:
MyProject/
MyProject/src
MyProject/src/CMakeLists.txt (1)
MyProject/src/ProtoProject/CMakeLists.txt (2)
MyProject/src/ProtoProject/MyProject/foo.proto
CMakeLists.txt (1):
add_subdirectory(MyProject)
# generated headers
target_include_directories(ProtoProject PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
CMakeLists.txt (2):
set(proto_files "foo.proto")
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${proto_files})
add_library(ProtoProject STATIC ${PROTO_SRCS} ${PROTO_HDRS} ${proto_files})
Why this works
Each call to add_subdirectory() adds a directory level to the $CMAKE_CURRENT_BINARY_DIRECTORY variable. The generated files will end up at MyProject/src/ProtoProject/MyProject/foo.pb.h but your include directory will be MyProject/src/ProtoProject, so you can include files as MyProject/foo.pb.h