CMake protobuf external to application code - cmake

Basically, I want to have my structure like such:
MainRepo
+---app1
+---app2
+---common
+---some_lib1
+---some_lib2
+---protobuf
+---comms.proto
+---cs
+---Comms.pb.cs
+---cpp
+---comms.pb.cc
+---comms.pb.h
I want to be able to check out the repo and have a script that runs protoc for all the different languages for the apps that are in the repo. This is a mono repo containing an app for two different arm machines and an x64. I essentially are running protoc and it generates all the source files for c, js, cs, cpp, etc and puts them under protobuf in their own folders.
I want to have app1, for example, go find the c++ header and source and use them to build the app. At the moment, the example I have been hacking, uses cmake to generate the .cc and .h which makes it inconvenient for me as intellisense complains since those files dont exist when I'm writing.
Anyway, I've been hacking away at cmake all day. I always end up with cmake having a forward declaration error and cant compile my .cc and .h
PROJECT(test)
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")
ADD_EXECUTABLE(main main.cpp)
TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})
find_package(Protobuf REQUIRED)
set(PROTOBUF_IMPORT_DIRS "../proto")
set (msgs ${PROTOBUF_IMPORT_DIRS}/communications.proto)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${msgs})
add_library(proto SHARED ${PROTO_SRCS})
target_link_libraries(proto ${PROTOBUF_LIBRARY})
Wondering if there are any suggestions. I dont want to have my protobuf stuff outside of my common folder and I also dont need protoc to generate those files either as I do that another way (although I could change that way). I just want to ensure that the language specific files are still available to view and not just generated during cmake and I cant view them.

My 2 cents,
Here this is what I did for google/or-tools
ref: https://github.com/google/or-tools
Protobuf Integration
I'm using Fetchcontent() (CMake >= 3.18 to have SOURCE_SUBDIR option IIRC), but I also need to patch it (e.g. to have CMP0077)
you can find the protobuf patch here: https://github.com/google/or-tools/blob/stable/patches/protobuf-v3.12.2.patch
cmake/dependencies/CMakeLists.txt
include(FetchContent)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BUILD_TESTING OFF)
message(CHECK_START "Fetching Protobuf")
list(APPEND CMAKE_MESSAGE_INDENT " ")
set(protobuf_BUILD_TESTS OFF)
set(protobuf_BUILD_EXPORT OFF)
set(protobuf_MSVC_STATIC_RUNTIME OFF)
# FetchContent_Declare(SOURCE_SUBDIR) was introduced in 3.18
FetchContent_Declare(
protobuf
GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
GIT_TAG "v3.12.2"
PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.12.2.patch"
SOURCE_SUBDIR cmake)
FetchContent_MakeAvailable(protobuf)
list(POP_BACK CMAKE_MESSAGE_INDENT)
message(CHECK_PASS "fetched")
ref: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dependencies/CMakeLists.txt#L142-L168
note: for cmake < 3.18, I use ExternalProject + execute_process()
see: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/utils.cmake#L66-L137
Generate Protobuf files
Since we have integrated Protobuf, now we have access to protobuf::protoc.
To build proto file, simply adapt
# Get Protobuf include dirs
get_target_property(protobuf_dirs protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir IN LISTS protobuf_dirs)
if ("${dir}" MATCHES "BUILD_INTERFACE")
message(STATUS "Adding proto path: ${dir}")
list(APPEND PROTO_DIRS "--proto_path=${dir}")
endif()
endforeach()
# Generate Protobuf cpp sources
set(PROTO_HDRS)
set(PROTO_SRCS)
file(GLOB_RECURSE proto_files RELATIVE ${PROJECT_SOURCE_DIR}
"common/protobuf/*.proto"
)
foreach(PROTO_FILE IN LISTS proto_files)
#message(STATUS "protoc proto(cc): ${PROTO_FILE}")
get_filename_component(PROTO_DIR ${PROTO_FILE} DIRECTORY)
get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE)
set(PROTO_HDR ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.h)
set(PROTO_SRC ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.cc)
#message(STATUS "protoc hdr: ${PROTO_HDR}")
#message(STATUS "protoc src: ${PROTO_SRC}")
add_custom_command(
OUTPUT ${PROTO_SRC} ${PROTO_HDR}
COMMAND protobuf::protoc
"--proto_path=${PROJECT_SOURCE_DIR}"
${PROTO_DIRS}
"--cpp_out=${PROJECT_BINARY_DIR}"
${PROTO_FILE}
DEPENDS ${PROTO_FILE} protobuf::protoc
COMMENT "Generate C++ protocol buffer for ${PROTO_FILE}"
VERBATIM)
list(APPEND PROTO_HDRS ${PROTO_HDR})
list(APPEND PROTO_SRCS ${PROTO_SRC})
endforeach()
ref: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/cpp.cmake#L234-L279
After you can use PROTO_HDR and PROTO_SRC e.g. add them to your target sources etc...
note: for .Net you can take a look at
https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dotnet.cmake#L30-L60
All in all, just adapt to your need, e.g. generate in source tree than binary dir etc. and you should be able to do whatever you want...

Related

Why does the following CMakeLists.txt cannot generate the output file of series of *.proto(protobuf)

I am not familiar with cmake and protobuf. I want to write a CMakeLists.txt to help me generate all protobuf file in a specified directory into another specified directory.
The following is the CMakeLists.txt I writen, but it cannot generate any *.pb.h or *.pb.cc now. Anyone can tell me what's wrong with my CMakeLists.txt? Thanks.
The cmake vesion I used is 3.12 and protoc version is 3.12.
file(GLOB_RECURSE children LIST_DIRECTORIES true "${CMAKE_CURRENT_SOURCE_DIR}/protos/*.proto")
SET(PROTO_META_BASE_DIR ${CMAKE_CURRENT_BINARY_DIR}/protos_cpp_hpp)
FOREACH(FIL ${children})
GET_FILENAME_COMPONENT(ABS_FIL ${FIL} ABSOLUTE)
GET_FILENAME_COMPONENT(FIL_WE ${FIL} NAME_WE)
LIST(APPEND PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/protos_cpp_hpp/${FIL_WE}.pb.cc")
LIST(APPEND PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/protos_cpp_hpp/${FIL_WE}.pb.h")
# EXECUTE_PROCESS(
# COMMAND PROTOBUF_GENERATE_CPP --cpp_out=${PROTO_META_BASE_DIR} ${FIL}
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/protos
# )
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HDR ${CMAKE_SOURCE_DIR}/protos/${FIL})
ENDFOREACH()
According to the documentation, the function PROTOBUF_GENERATE_CPP creates a custom command which OUTPUT lists resulted files. So, nothing will be generated unless there is a target which consumes these files as a dependency.
The most direct way is consuming the files as sources for add_executable:
add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS})
This way is described in the documentation.
If, for some reason, you don't want create anything from the resulted files, then you may create a custom target which consumes these files:
add_custom_target(my_command ALL DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})

How to find static version of zlib in CMake?

I'm on cmake version 3.12.1 and want to build a static executable that uses ZLIB. I have both the static (libz.a) and shared (libz.so) libraries on my machine. How can I tell find_package(ZLIB) to return the static version? Maybe there's another way to find libz.a as well?
My present workaround is to specify:
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
Then:
target_link_libraries (my_binary z lib1 lib2)
Critique on this approach is also welcome!
As of CMake 3.24, use: set(ZLIB_USE_STATIC_LIBS "ON")
Source
Your approach is valid given the limitations of the CMake module called by find_package(ZLIB), specifically FindZLIB.cmake. While other FindXXX.cmake modules have a special option for grabbing static libraries, the zlib module does not.
There are already a few questions on SO about this topic, but some are older than others, so there are a few options.
You can instead apply the -static flag on a more granular level (rather than editing the global CMAKE_EXE_LINKER_FLAGS variable) by adding it to your target_link_libraries call. This way it will apply only to that target -- useful if you are building other non-static targets.
You could also tell CMake to search for static libraries explicitly by setting CMAKE_FIND_LIBRARY_SUFFIXES. When find_package is called, CMake can search for libraries ending in .a using this:
SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
find_package(ZLIB REQUIRED)
If you have control over installing zlib, for example, you are installing dependencies in a Continuous Integration setup, I would recommend to just remove the zlib dynamic library.
zlib doesn't have the option to build statically or dynamically, it automatically generates both versions. However FindZlib.cmake prioritizes the dynamic version.
I find the following approach to be better in case you don't have access to modify third parties repositories CMakeLists.txt that needs zlib:
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(_compiler_is_msvc ON)
endif()
option(ZLIB_FORCE_STATIC "Remove the dynamic libraries after zlib install" ON)
mark_as_advanced(ZLIB_FORCE_STATIC)
set(OUTPUT_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Base folder where builds and source folder will be installed: i.e. OUTPUT_BUILD_DIR/zlib")
if(_compiler_is_msvc)
set(ZLIB_GIT_TAG cacf7f1d4e3d44d871b605da3b647f07d718623f) # Version 1.2.11
message(STATUS "ZLIB_VERSION: ${ZLIB_GIT_TAG} : Version 1.2.11")
set(ZLIB_BUILD_DIR ${OUTPUT_BUILD_DIR}/zlib-build)
set(ZLIB_INSTALL_DIR ${OUTPUT_BUILD_DIR}/zlib)
set(ZLIB_SRC_FOLDER_NAME zlib-src)
set(ZLIB_SRC_DIR ${OUTPUT_BUILD_DIR}/${ZLIB_SRC_FOLDER_NAME})
set(ZLIB_GIT_REPOSITORY "https://github.com/madler/zlib")
ExternalProject_Add(ep_zlib
GIT_REPOSITORY ${ZLIB_GIT_REPOSITORY}
GIT_TAG ${ZLIB_GIT_TAG}
# GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
CMAKE_GENERATOR ${CMAKE_GENERATOR}
SOURCE_DIR ${ZLIB_SRC_DIR}
BINARY_DIR ${ZLIB_BUILD_DIR}
CMAKE_ARGS
-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
-DCMAKE_BUILD_TYPE:STRING=${SGEXT_CMAKE_BUILD_TYPE}
-DBUILD_SHARED_LIBS:BOOL=OFF
-DCMAKE_INSTALL_PREFIX=${ZLIB_INSTALL_DIR}
)
if(ZLIB_FORCE_STATIC)
ExternalProject_Add_Step(
ep_zlib zlib_remove_dll
COMMENT "Remove zlib.lib and zlib.dll, leaves only zlibstatic.lib"
DEPENDEES install
COMMAND ${CMAKE_COMMAND} -E remove -f ${ZLIB_INSTALL_DIR}/lib/zlib.lib ${ZLIB_INSTALL_DIR}/bin/zlib.dll
)
endif()
endif()
The last step removes the dynamic version, so the default FindZLIB will find the static library.
The best solution I found was to name the library explicitly when calling CMake:
cmake -DZLIB_LIBRARY=/usr/lib/x86_64-linux-gnu/libz.a /path/to/source
I would not recommend the solution proposed by #phcerdan because in my case the installed shared library was colliding with an already installed version, so the only solution was to make sure it never gets installed in the first place. The key idea is to disable completely the targets installation using SKIP_INSTALL_LIBRARIES, and instead to "install" the static library manually. Nonetheless, my solution is quite similar:
EXTERNALPROJECT_ADD(zlib_external
GIT_REPOSITORY https://github.com/madler/zlib.git
GIT_TAG v1.2.11
CMAKE_ARGS
-DSKIP_INSTALL_FILES=ON # Disable install of manual and pkgconfig files
-DSKIP_INSTALL_LIBRARIES=ON # Do not install libraries automatically. It will be handled manually to avoid installing shared libs
-DBUILD_SHARED_LIBS=OFF
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX}
-DCMAKE_C_FLAGS:STRING=${CMAKE_COMPILE_FLAGS_EXTERNAL}
${EXTERNALPROJECT_BUILD_TYPE_CMD}
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
)
if(NOT WIN32)
set(zlib_BUILD_LIB_PATH "<BINARY_DIR>/libz.a")
set(zlib_PATH "${CMAKE_INSTALL_PREFIX}/lib/libz.a")
else()
set(zlib_BUILD_LIB_PATH "<BINARY_DIR>/Release/zlibstatic.lib")
set(zlib_PATH "${CMAKE_INSTALL_PREFIX}/lib/zlibstatic.lib")
endif()
ExternalProject_Add_Step(
zlib_external zlib_install_static_only
COMMENT "Manually installing only static library"
DEPENDEES install
COMMAND ${CMAKE_COMMAND} -E copy ${zlib_BUILD_LIB_PATH} ${zlib_PATH}
)

CMake target dependency to compile protobuf files

I want to build a c++ static lib out of some protobuf definitions with cmake/make.
I made a custom COMMAND to compile the protobuf to c++, and I set it as a PRE_BUILD dependency to my static lib.
project(mylib)
set(PROTO_PATH "${CMAKE_CURRENT_SOURCE_DIR}/proto_definitions")
file(GLOB PROTO_FILES "${PROTO_PATH}/*.proto")
foreach(PROTO_FILE in ${PROTO_FILES})
string(REGEX REPLACE "[.]proto$" ".pb.cc" OUTPUT_SOURCE ${PROTO_FILE})
list(APPEND OUTPUT_SOURCES ${OUTPUT_SOURCE})
endforeach()
add_custom_command(TARGET ${PROJECT_NAME}
PRE_BUILD
COMMAND protoc --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/compiled_proto ${PROTO_FILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "some comment")
add_library(${PROJECT_NAME} STATIC ${OUTPUT_SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
I get the following error when running cmake:
CMake Error: cannot determine link language for target "mylib"
Regardless of this error, the makefiles are generated, but when I make mylib, it does not trigger any proto compilation
The approach more native to CMake would be to add custom commands with the OUTPUT signature to generate the .cc files, and then use them as sources for the library normally. That way, they CMake will know what they are and how to produce them:
project(mylib)
set(PROTO_PATH "${CMAKE_CURRENT_SOURCE_DIR}/proto_definitions")
file(GLOB PROTO_FILES "${PROTO_PATH}/*.proto")
foreach(PROTO_FILE in ${PROTO_FILES})
string(REGEX REPLACE "[.]proto$" ".pb.cc" OUTPUT_SOURCE ${PROTO_FILE})
list(APPEND OUTPUT_SOURCES ${OUTPUT_SOURCE})
endforeach()
add_custom_command(OUTPUT ${OUTPUT_SOURCES}
COMMAND protoc --cpp_out=${CMAKE_CURRENT_SOURCE_DIR}/compiled_proto ${PROTO_FILES}
DEPENDS ${PROTO_FILES}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "some comment")
add_library(${PROJECT_NAME} STATIC ${OUTPUT_SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
Done this way, there will be one command which reads all the .proto files and produces all the .cc files — which means that if any of the .proto file changes, all the .cc files will be re-generated. I am not familiar with Protobuffers so I cannot know whether that's sane or not. If they are independent, it would be better to introduce one add_custom_command for each output file.
Also, given the arguments you're passing to protocc, you might have to modify the paths in OUTPUT_SOURCES to correctly point to the generated files.
Also note that CMake comes with a FindProtobuf module which defines a protobuf_generate_cpp() command, so you might want to use that instead of hand-coding the Protobuf support.
Comment for the answer above: There is no in in cmake foreach, which spend me some time to solve it.
After studying his answer(very thanks!), I summarized a method that works for me, which has the following characteristics:
Proto dir and Output dir can be different
Generate grpc_output
Create a custom_command for each proto
My project strcuture is:
hwpb/ (a library for super project)
cpp/
hwpb/ (store *.pb.cc, *.pb.h)
CMakeLists.txt
proto/ (store protos)
go/ (and other languages, not mentioned here)
And this is my CMakeListx.txt:
set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../proto")
set(OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/hwpb")
file(GLOB PROTO_FILES "${PROTO_DIR}/*.proto")
foreach(PROTO_FILE ${PROTO_FILES})
get_filename_component (FILENAME ${PROTO_FILE} NAME_WLE)
set(PROTO_SRC "${OUTPUT_DIR}/${FILENAME}.pb.cc")
set(PROTO_HDR "${OUTPUT_DIR}/${FILENAME}.pb.h")
set(GRPC_SRC "${OUTPUT_DIR}/${FILENAME}.grpc.pb.cc")
set(GRPC_HDR "${OUTPUT_DIR}/${FILENAME}.grpc.pb.h")
add_custom_command(
OUTPUT "${PROTO_SRC}" "${PROTO_HDR}" "${GRPC_SRC}" "${GRPC_HDR}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --plugin=protoc-gen-grpc=${_GRPC_CPP_PLUGIN_EXECUTABLE}
--cpp_out="${OUTPUT_DIR}" --grpc_out="${OUTPUT_DIR}"
-I"${PROTO_DIR}" "${PROTO_FILE}"
DEPENDS ${PROTO_FILE}
)
list(APPEND OUTPUT_SOURCES ${PROTO_SRC} ${GRPC_HDR})
endforeach()
add_library(hwpb ${OUTPUT_SOURCES})
target_link_libraries(hwpb ${_GRPC_GRPCPP_UNSECURE} ${_PROTOBUF_LIBPROTOBUF})
target_include_directories(hwpb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

how to use CMake file (GLOB SRCS *. ) with a build directory

this is my current CMakeLists.txt file
cmake_minimum_required(VERSION 3.3)
set(CMAKE_C_FLAGS " -Wall -g ")
project( bmi )
file( GLOB SRCS *.cpp *.h )
add_executable( bmi ${SRCS})
This builds from my source directory, but I have to clean up all the extra files after. My question is how do I build this from a build directory if all my source files are in the same source directory?
thanks
If you really need to use file(GLOB …), this CMakeLists.txt should work :
cmake_minimum_required(VERSION 3.3)
project(bmi)
add_definitions("-Wall" "-g")
include_directories(${PROJECT_SOURCE_DIR})
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
add_executable(bmi ${SRC_FILES})
In this case you have to launch cmake from your build directory every time you add or delete a source file :
cmake <your_source_dir> -G <your_build_generator>
As Phil reminds, CMake documentation doesn't recommend this use of GLOB. But there are some exceptions. You'll get more information on this post.
If you don't meet those exceptions, you'd rather list your source files than use GLOB :
set(SRC_FILES ${PROJECT_SOURCE_DIR}/main.cpp
${PROJECT_SOURCE_DIR}/bmi.cpp
… )
NB : if you have #include of your .h files in .cpp files, I don't see any reason to put them in add_executable, you just need to specify include directory with include_directories.
Cmake used to only update the list of source files if CMakeLists.txt was changed since the last cmake run or if cmake was used to configure the project again.
In cmake 3.11.0 recursive search and automatic re-configuration on adding or deleting source files was added. Since then you can use the following snippet:
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0")
file(GLOB_RECURSE SOURCE_FILES CONFIGURE_DEPENDS *.cpp *.h)
else()
file(GLOB SOURCE_FILES *.cpp *.h */*.h */*.cpp)
endif()
The file() command after the else() provides at least a bit of backwards compatibility: It still searches for source files in the current folder and its direct subfolders. But it doesn't automatically recognize if there are new files or old files have been deleted.
Note that VERSION_GREATER_EQUAL is only available in cmake >= 3.7

custom target as a target library in cmake

I have a custom target that is in fact an externally generated library that I want to integrate in my build.
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/liblib2.a
COMMAND make -f ${CMAKE_CURRENT_SOURCE_DIR}/makefile liblib2.a)
add_custom_target(lib2
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/liblib2.a)
How can I tell cmake that this target is in fact a library, where it can be found and where are the headers ?
To be clear : I don't want the upper CMakeList using this library having to manually specify include folders and the library location folder It must be done automatically (from the target properties).
On a standard cmake library I would just have to add the INTERFACE_INCLUDE_DIRECTORIES property in the library CMakeLists to make cmake link my app with the relevant -I and -L gcc parameters :
set_target_properties(lib1
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR})
But in the case of a custom target I don't know how to to it.
Any clue ?
Thanks for your help.
Thanks to zaufi it works!
For others who may be interested in embedded externally build target inside cmake here is what I did :
cmake_minimum_required(VERSION 2.8)
SET(LIB_FILE ${CMAKE_CURRENT_SOURCE_DIR}/bin/liblib2.a)
SET(LIB_HEADER_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/include)
# how to build the result of the library
add_custom_command(OUTPUT ${LIB_FILE}
COMMAND make
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# create a target out of the library compilation result
add_custom_target(lib2_target DEPENDS ${LIB_FILE})
# create an library target out of the library compilation result
add_library(lib2 STATIC IMPORTED GLOBAL)
add_dependencies(lib2 lib2_target)
# specify where the library is and where to find the headers
set_target_properties(lib2
PROPERTIES
IMPORTED_LOCATION ${LIB_FILE}
INTERFACE_INCLUDE_DIRECTORIES ${LIB_HEADER_FOLDER})
Now in a CMakeLists.txt I can do somthing like
add_subdirectory(${ROOT_DIR}/lib1 bin/lib1)
add_subdirectory(${ROOT_DIR}/lib2 bin/lib2)
add_executable(app app.c )
target_link_libraries(app lib1 lib2)
No need to specify where the .a and the .h are.
You can use add_library() and tell that it actually imported. Then, using set_target_properties() you can set required INTERFACE_XXX properties for it. After that, you can use it as an ordinal target like every other built by your project.
Thank you for posting the solution. I have wrapped your snippet in a function:
function(add_external_library)
set(options)
set(oneValueArgs TARGET WORKING_DIRECTORY OUTPUT COMMENT)
set(multiValueArgs COMMAND INCLUDE_DIRS)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" ${multiValueArgs}" ${ARGN})
# Specify how to build the result of the library
add_custom_command(OUTPUT "${ARGS_OUTPUT}"
COMMAND ${ARGS_COMMAND}
WORKING_DIRECTORY "${ARGS_WORKING_DIRECTORY}"
COMMENT "${ARGS_COMMENT}")
# Create a target out of the library compilation result
add_custom_target(${ARGS_TARGET}_target DEPENDS ${ARGS_OUTPUT})
# Create an library target out of the library compilation result
add_library(${ARGS_TARGET} STATIC IMPORTED GLOBAL)
add_dependencies(${ARGS_TARGET} ${ARGS_TARGET}_target)
# Specify where the library is and where to find the headers
set_target_properties(${ARGS_TARGET}
PROPERTIES
IMPORTED_LOCATION "${ARGS_OUTPUT}"
INTERFACE_INCLUDE_DIRECTORIES "${ARGS_INCLUDE_DIRS}")
endfunction()
# Example
add_external_library(TARGET YourLib
COMMAND /bin/bash compile_your_lib.sh
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT "output/yourlib.a"
INCLUDE_DIRS "include/a" "include/b"
COMMENT "Building YourLib")
add_executable(YourExe)
target_link_libraries(YourExe YourLib)