Linking multiple objects files generated by Makefile to CMake subdirectory - c++

I have a list of object files generated by a Makefile stored under say mylib directory. I am trying to link these object files while compiling one of the sub-directories in my project (I don't want to generate an executable). Here is my CMakeLists.txt file
cmake_minimum_required(VERSION 3.5.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g")
set( CMAKE_EXPORT_COMPILE_COMMANDS ON )
file(GLOB SOURCES "*.cpp" ".hpp")
include_directories(mylib)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/mylib)
add_library(slib SHARED ${SOURCES})
That is, mylib directory contains .h, .cc and .o files I generated after running make on mylib.
When I try to compile this, I get an Undefined symbols for architecture x86_64 error for mylib functions.
How can I link multiple precompiled object files generated by an external make? This question (how to add prebuilt object files to executable in cmake) gives a method to link a single object file. How do I do this for all the object files and generated a shared library instead of an executable?

I suggest to compile library "mylib" with ExternalProject (by direct call to gcc, for example) and, then use code like this:
add_library (slib SHARED ${SOURCES})
target_link_libraries (slib "mylib")
add_dependencies may be useful in some cases.

Related

CMake to give (.o) file as output

I'm trying to get mu C++ code to compile as object file (.o) but I can get it in (.a, .dylib, executable) forms
I've tried this answer: Copy out plain .o files with cmake
but didn't actually understood the solution and it didn't work either.
how can I achieve this ?
here is my CMake file:
cmake_minimum_required(VERSION 3.10)
project(myProject)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(LIBS_DIR ${PROJECT_SOURCE_DIR}/../libs)
file(GLOB SOURCES
src/*.cpp
)
find_library(SQLITE3
NAMES libsqlite3.0.tbd
)
MACRO(HEADER_DIRECTORIES return_list)
FILE(GLOB_RECURSE new_list ${LIBS_DIR}/*.h*)
SET(dir_list "")
FOREACH(file_path ${new_list})
GET_FILENAME_COMPONENT(dir_path ${file_path} PATH)
SET(dir_list ${dir_list} ${dir_path})
ENDFOREACH()
LIST(REMOVE_DUPLICATES dir_list)
SET(${return_list} ${dir_list})
ENDMACRO()
add_library(${PROJECT_NAME}_obj OBJECT ${SOURCES})
HEADER_DIRECTORIES(HDR_DIRS)
target_include_directories(${PROJECT_NAME}_obj PUBLIC
${PROJECT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/../fmt
${PROJECT_SOURCE_DIR}/../include
${HDR_DIRS}
)
target_link_libraries(${PROJECT_NAME}_obj ${SQLITE3})
You cannot merge multiple translation units into a single object file (is due to the features of the linker (ld util). only to library or elf.
Earlier gcc can to be able to merge several files into a single object file, but this feature was removed

Separate CUDA compilation with CMAKE

I want to compile .cu and .cpp to .o files separately, then link them to executable. I have few simple files: cuda_func.cu. cuda_func.h and main.cpp. In main cpp I include cuda_func.h and run cuda_func(). I've come up with following cmake code:
project(cuda)
cmake_minimum_required(VERSION 2.8)
# CUDA PACKAGE
find_package(CUDA REQUIRED)
set(CUDA_SEPARABLE_COMPILATION ON)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
set(CUDA_HOST_COMPILER g++)
# COMPILE CU FILES
file(GLOB CUDA_FILES *.cu)
list( APPEND CUDA_NVCC_FLAGS "-gencode arch=compute_30,code=sm_30; -std=c++11")
CUDA_COMPILE(CU_O ${CUDA_FILES})
SET(CMAKE_EXE_LINKER_FLAGS "-L/usr/local/cuda/lib -lcudart")
# SETUP FOR CPP FILES
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# COMPILE AND LINK
add_executable(main main.cpp ${CU_O})
But I get undefined reference to "cudaMemcpy" error. When I compile it by hand, using nvcc and g++ to get .o files and g++ finally to make executable it works fine. It seems like the cuda library isnt linked properly at the end. What should I do?
Cmake 3.8 added native support for CUDA (here is a document from NVIDIA that explains how to use it this way), you can simply add cuda as a language and the appropriate compiler will be used automatically for each file.
cmake_minimum_required (VERSION 3.8)
project(youProject LANGUAGES CXX CUDA)
add_executable(yourExecutable)
target_sources(yourExecutable <you can add c++ as well as cuda files here>)
// Or if you want to separate cuda and C++ more clearly, put your cuda code
// in a library and link to it (which obviously allows you to compile them separately)
add_library(yourCudaLib <you can add your cuda files here>)
target_link_libraries(yourProject PRIVATE yourCudaLib)

Should I use only add_executable() with raw cpp files or make a library via add_library()?

I'm learning CMake and I'm struggling with it a little. My "project" is using JsonCpp "library" that was provided as one .cpp file and two .h files. The structure looks like this:
myProject
build/
json/
CMakeLists.txt
jsoncpp.cpp
include/
json.h
json-forward.h
CMakeLists.txt
main.cpp
build/CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
project(myProject)
add_subdirectory(json)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE json)
# add_executable(app main.cpp json/jsoncpp.cpp json/include/json.h json/include/json-forwards.h)
json/CMakeLists.txt:
cmake_minimum_required(VERSION 3.6.0)
add_library(
json
jsoncpp.cpp
include/json.h
include/json-forwards.h
)
target_include_directories(json PUBLIC '${CMAKE_CURRENT_SOURCE_DIR}/include')
What's a difference between using only add_executable() with all .cpp files and using target_link_libraries that transforms jsoncpp into static library and then link it? What approach should I choose?
A next thing confusing me is a target_include_directories(). What are the benefits using this function? If I comment it, and run cmake (then makefile and launch the app) everything still works fine. If I delete "include/json.h" "include/json-forward.h" from add_library(), everything still works.
What's a difference between using only add_executable() with all .cpp files and using target_link_libraries that transforms jsoncpp into static library and then link it? What approach should I choose?
Using add_library is required when you have 2 executables using the same jsoncpp code. In this case, if you list jsoncpp sources in both add_executable() calls, you'd have to compile it twice. Grouping them into add_library() will make it compile only once and then linked to both executables.
Another reason to use add_library is purely logical composition of modules.

Compiling/adding cuda code to existing project (CMake)

I am trying to port parts of an existing project to GPUs via CUDA code. I understand cmake has options (find_cuda...) to deal with .cu files separately, yet I am still trying to figure out how this ecosystem can be used in context of existing projects.
My question is the following. Let's say I have an existing C++ project with a cmake config file (CMakeLists). What is the current practice to eleganly (if possible) include CUDA kernels? Can CMakeLists be constructed in a way, .cu files are compiled only if GPU is present?
My current idea is to create a separate folder, where only CUDA related code exists and then compile this as a static library. Is that the way to do it?
Having the CUDA files in separate folders is my recommended way but not required. The basic principle is that you collect all .cu files in a CMake variable (let's call it CUDA_SRC) and all .cpp files in a different variable (call it SRC). Now you compile both files and put them together. The variable CUDA_FOUND provided by find_package(CUDA) can be used to determine if CUDA is installed on your system. The use of a static library for the cuda files is not required, but i'll show you both ways here.
In your top level cmake file you want to have something like this to find CUDA and set some nvcc flags:
find_package(CUDA QUIET)
if(CUDA_FOUND)
include_directories(${CUDA_INCLUDE_DIRS})
SET(ALL_CUDA_LIBS ${CUDA_LIBRARIES} ${CUDA_cusparse_LIBRARY} ${CUDA_cublas_LIBRARY})
SET(LIBS ${LIBS} ${ALL_CUDA_LIBS})
message(STATUS "CUDA_LIBRARIES: ${CUDA_INCLUDE_DIRS} ${ALL_CUDA_LIBS}")
set(CUDA_PROPAGATE_HOST_FLAGS ON)
set(CUDA_SEPARABLE_COMPILATION OFF)
list( APPEND CUDA_NVCC_FLAGS -gencode=arch=compute_30,code=compute_30 )
list( APPEND CUDA_NVCC_FLAGS -gencode=arch=compute_52,code=sm_52 )
endif()
With static CUDA library
if(CUDA_FOUND)
#collect CUDA files
FILE(GLOB_RECURSE CUDA_SRC *.cu)
#build static library
CUDA_ADD_LIBRARY(my_cuda_lib ${CUDA_SRC} STATIC)
SET(LIBS ${LIBS} ${my_cuda_lib})
endif()
#collect cpp files
FILE(GLOB_RECURSE SRC *.cpp)
#compile .cpp files and link it to all libraries
add_executable(${PROG_NAME} ${SRC})
target_link_libraries(${PROG_NAME} ${LIBS} )
Without Static CUDA lib
FILE(GLOB_RECURSE SRC *.cpp)
if(CUDA_FOUND)
#compile cuda files and add the compiled object files to your normal source files
FILE(GLOB_RECURSE CUDA_SRC *.cu)
cuda_compile(cuda_objs ${CUDA_SRC})
SET(SRC ${SRC} ${cuda_objs})
endif()
#compile .cpp files and link it to all libraries
add_executable(${PROG_NAME} ${SRC})
target_link_libraries(${PROG_NAME} ${LIBS} )

CMake finds more than one main function

I am trying to compile a project that has only one main function, but CMake find more.
My CMakeLists.txt is like:
cmake_minimum_required(VERSION 2.8)
project(my_proj)
include_directories(".")
add_subdirectory(main)
add_subdirectory(resources)
find_package(OpenCV REQUIRED)
find_package(Boost REQUIRED COMPONENTS system regex program_options)
include_directories(${Boost_INCLUDE_DIRS})
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE HDR_FILES ${PROJECT_SOURCE_DIR}/*.hpp)
add_executable(my_proj ${SRC_FILES} ${HDR_FILES})
target_link_libraries(my_proj ${OpenCV_LIBS})
target_link_libraries(my_proj ${OpenCV_LIBS}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_REGEX_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY})
I have more folders with .hpp and .cpp files that is why I have added file(GLOB_RECURSE... statements and also include_directories(".").
I get an error after it compiles all files that says:
CMakeFiles/my_proj.dir/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp.o: In function `main':
/media/N/my_proj/build/CMakeFiles/CompilerIdCXX/CMakeCXXCompilerId.cpp:209: multiple definition of `main'
CMakeFiles/my_proj.dir/main.cpp.o:/media/N/my_proj/main.cpp:10: first defined here
CMakeFiles/my_proj.dir/main/solution2/sources/CRunSolution2.cpp.o: In function `boost::filesystem3::path::codecvt()':
/usr/include/boost/filesystem/v3/path.hpp:377: undefined reference to `boost::filesystem3::path::wchar_t_codecvt_facet()'
Has anyone met something like that? If yes, how to fix it?
In your executable you simply have 2 main functions (print out SRC_FILES by MESSAGE(${SRC_FILES})). One is in main.cpp and one in CMakeCXXCompilerId.cpp (which is a file that CMake generates to test if your CXX compiler works correctly). The GLOB_RECURSE probably finds and adds both of these files to SRC_FILES
Using FILE(GLOB ...) is tricky:
We do not recommend using GLOB to collect a list of source files from your source tree. If no CMakeLists.txt file changes when a source is added or removed then the generated build system cannot know when to ask CMake to regenerate.
You should list your source and header files in your CMakeLists.txt directly