Build CUDA library using Xcode and CMake fail - c++

I am trying to use CMake to generate a Xcode project and build a CUDA library with it.
The code I used for collecting & building CUDA library "caffe2_cpp_gpu" is as follows:
list(APPEND CUDA_NVCC_FLAGS "-std=c++11" "-Wno-deprecated-gpu-targets")
file(GLOB CUDA_SOURCES "${PROJECT_SOURCE_DIR}/source/caffe2/operator/*.cu" )
cuda_add_library(caffe2_cpp_gpu STATIC ${CUDA_SOURCES})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang++" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
list(APPEND ALL_LIBRARIES -Wl,-force_load caffe2_cpp_gpu)
else()
list(APPEND ALL_LIBRARIES -Wl,--whole-archive caffe2_cpp_gpu -Wl,--no-whole-archive)
endif()
Note that this code can be run if Unix Makefile is used.
But cannot run if Xcode is used.
In the project it shows a file is missing:
missing file
And the CUDA library "caffe2_cpp_gpu" cannot be created.
Does anyone know how to solve it?

I found the answer...
If I append another kind of file (.cc, .h, etc.) into the CUDA libary, it will work. It seems like XCode cannot build single .cu file into static library (.a).
So here is what I did:
file(GLOB All_SOURCE "${PROJECT_SOURCE_DIR}/source/caffe2/operator/*.cu" "${PROJECT_SOURCE_DIR}/source/caffe2/operator/*.cc" "${PROJECT_SOURCE_DIR}/source/caffe2/operator/*.h")
cuda_add_library(caffe2_lib ${All_SOURCE})
Instead of building library seperately for CPU and GPU. I merge them into a single library file.

Related

FreeType2 Cross-compiling for Android

I was able to compile Freetype2 library for arm, arm64, x86, x86_64 architectures. These are steps I done to compile it.
Created standalone toolchains for architectures mentioned above.
make_standalone_toolchain.py \
--arch arm64 \
--api 26 \
--stl=libc++ \
--install-dir=my-arm64-toolchain
Set some envirement variables
export PATH=$PATH:`pwd`/my-toolchain/bin
target_host=aarch64-linux-android
export AR=$target_host-ar
export AS=$target_host-as
export CC=$target_host-gcc
export CXX=$target_host-g++
export LD=$target_host-ld
export STRIP=$target_host-strip
export CFLAGS="-fPIE -fPIC"
export LDFLAGS="-pie"
Configure freetype for compilation
./configure --host=aarch64-linux-android --prefix=/home/freetype-arm64 --without-zlib --without-harfbuzz --with-png=no
And finally make && install
Compilation was successfull and I was able to get Static freetype library.
I added library to my android studio libs folder.
This is folder structure for library:
libs---freetype
|---${ANDROID_ABI}
|---include
|---freetype2
|---freetype
---|Bunch of header files
|---ftbuild.h
|---lib
|---libfreetype.a
This is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
add_definitions("-DGLM_FORCE_SIZE_T_LENGTH -DGLM_FORCE_RADIANS")
add_subdirectory(src/main/cpp/glm)
add_library(freetype STATIC IMPORTED)
set_target_properties(freetype PROPERTIES IMPORTED_LOCATION${PROJECT_SOURCE_DIR}/libs/freetype/${ANDROID_ABI}/lib/libfreetype.a)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall")
add_library(native-lib SHARED
src/main/cpp/native-lib.cpp
src/main/cpp/graph.cpp
src/main/cpp/text.cpp
src/main/cpp/graphDataWorker.cpp
)
target_include_directories(native-lib PRIVATE ${PROJECT_SOURCE_DIR}/libs/freetype/${ANDROID_ABI}/include/freetype2)
target_link_libraries(native-lib
android
freetype
GLESv2
EGL
glm
atomic
log
OpenSLES
)
The problem is that I can use library inside my code and android studio is not giving me any errors, but then i try to run application it gives me this error:
linker command failed with exit code 1 (use -v to see invocation)
PS: I Can't see freetype headers in android studio file tree aswell, but can see other libraries.
Question: Am I importing library in a wrong way or this is cross-compilation issue and if so how to do it properly?
I done a lot of research on this issue and was unable to find a solution
Any help will be appreciated.
Unless you mixed paths when installing your build of FreeType2, it seems that the compilation of the library is incorrect, since the linker complains about the library being for x86_64 architecture.
On Linux, usually you can check the architecture the library is built for with command file. Another way to check the architecture is to use the objdump tool that is shipped with Android NDK (if I remember correctly it is generated with a toolchain as well). Its name follows the same pattern than the compiler/linker/... tools, $target_host-objdump.
I would recommend to compile FreeType2 using CMake instead of autotools, at least in my case I successfully did it that way.
Here is a sample of CMake configuration I wrote to cross-compile FreeType2 for Android. It is a little complex because it is part of a project where I build several libraries.
The idea is that my CMake configuration uses ExternalProject to download and compile Freetype. My top-level CMakeLists.txt contains:
# CMakeLists.txt
set(DEVENV_CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}
-DCMAKE_C_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_C_FLAGS_${BUILD_TYPE}=${CMAKE_C_FLAGS_${BUILD_TYPE}}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_CXX_FLAGS_${BUILD_TYPE}=${CMAKE_CXX_FLAGS_${BUILD_TYPE}}
-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}
-DCMAKE_CXX_EXTENSIONS=${CMAKE_CXX_EXTENSIONS}
)
if(BUILD_SHARED_LIBS)
list(APPEND DEVENV_CMAKE_ARGS -DBUILD_STATIC_LIBS=OFF -DLIBTYPE=SHARED)
else()
list(APPEND DEVENV_CMAKE_ARGS -DBUILD_STATIC_LIBS=ON -DLIBTYPE=STATIC)
endif()
if(DEFINED ANDROID_TOOLCHAIN_DIR)
get_filename_component(_toolchain_dir ${ANDROID_TOOLCHAIN_DIR} ABSOLUTE)
list(APPEND DEVENV_CMAKE_ARGS -DANDROID_TOOLCHAIN_DIR=${_toolchain_dir})
endif()
if(DEFINED CMAKE_ANDROID_ARCH_ABI)
list(APPEND DEVENV_CMAKE_ARGS -DCMAKE_ANDROID_ARCH_ABI=${CMAKE_ANDROID_ARCH_ABI})
endif()
if(CMAKE_TOOLCHAIN_FILE)
get_filename_component(_toolchain_file ${CMAKE_TOOLCHAIN_FILE} ABSOLUTE)
list(APPEND DEVENV_CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${_toolchain_file})
endif()
add_subdirectory(freetype)
So the variable DEVENV_CMAKE_ARGS contains appropriate CMake arguments for cross-compiling that reflect my current CMake configuration. Under directory freetype, the CMakeLists.txt contains:
# freetype/CMakeLists.txt
project(freetype)
include(ExternalProject)
if(NOT FREETYPE_GIT_REPOSITORY)
set(FREETYPE_GIT_REPOSITORY "https://git.savannah.gnu.org/git/freetype/freetype2.git")
endif()
set(FREETYPE_GIT_REPOSITORY "${FREETYPE_GIT_REPOSITORY}"
CACHE STRING "Git repository for library Freetype."
)
if(NOT FREETYPE_GIT_TAG)
set(FREETYPE_GIT_TAG "VER-2-9")
endif()
set(FREETYPE_GIT_TAG "${FREETYPE_GIT_TAG}"
CACHE STRING "Tag or branch of Git repository to build."
)
message(STATUS "Freetype Git repository: ${FREETYPE_GIT_REPOSITORY}")
message(STATUS "Freetype Git tag: ${FREETYPE_GIT_TAG}")
externalproject_add(freetype
GIT_REPOSITORY "${FREETYPE_GIT_REPOSITORY}"
GIT_TAG "${FREETYPE_GIT_TAG}"
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/freetype/src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/freetype/build"
CMAKE_ARGS ${DEVENV_CMAKE_ARGS}
)
Basically this CMakeLists.txt uses ExternalProject to download and compile FreeType2 in the build directory.
And I use a toolchain file for Android:
# android.cmake
set(CMAKE_SYSTEM_NAME "Android")
set(CMAKE_ANDROID_STANDALONE_TOOLCHAIN ${ANDROID_TOOLCHAIN_DIR})
Sorry if it is overly complex; it comes from a project where I was playing with cross-compiling for Android. I hope it helps anyway.

Linking of CUDA library in CMake

I am using CMake 3.10 and have a problem linking a compiled library to a test executable in CMake.
I searched a lot and found that in earlier versions there was a problem where you could not link intermediate libraries in the result executable. I was not able to tell if this was resolved or still an issue.
My CMake files look like this:
Algo:
cmake_minimum_required (VERSION 3.9)
project(${MODULE_NAME}_core LANGUAGES CXX CUDA)
add_subdirectory("${core_impl_dir}" implementation)
set(cuda_src "parallel/ParallelComputation.cu")
set(cuda_hdr "parallel/ParallelComputation.h")
add_library(${PROJECT_NAME} STATIC "${cuda_src}" "${cuda_hdr}"
)
target_include_directories (${PROJECT_NAME} PUBLIC "include/"
"parallel/"
)
source_group("parallel" FILES "${cuda_src}" "${cuda_hdr}")
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${MODULE_NAME})
Test:
project(${MODULE_NAME}_gtest LANGUAGES CXX CUDA)
add_subdirectory("${gtest_impl_dir}" implementation)
add_executable(${PROJECT_NAME} "${gtest_impl_src}")
target_link_libraries(${PROJECT_NAME} ${MODULE_NAME}_core)
enable_testing()
find_package(GTest REQUIRED)
include_directories("${GTEST_INCLUDE_DIRS}")
target_link_libraries(${PROJECT_NAME} ${GTEST_BOTH_LIBRARIES})
source_group("Implementation\\Source Files" FILES "${gtest_impl_src}" )
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER ${MODULE_NAME})
add_test(${PROJECT_NAME} ${PROJECT_NAME})
Building just Algo works fine, but when also building Test, I get linking errors, for example
../implementation/libmatrix1_testCuda_core.a(ParallelComputation.cu.o): In Funktion 'cudaError cudaMalloc(float**, unsigned long)':
tmpxft_00005ad0_00000000-5_ParallelComputation.cudafe1.cpp:(.text+0x4f2): Undefined reference 'cudaMalloc'
EDIT
using make VERBOSE=1 I got this linking command:
/usr/bin/c++ -Wl,--no-as-needed -pthread -g -std=c++14 -Wall
CMakeFiles/matrix1_testCuda_gtest.dir//tests/eclipseProject/algos/testCuda/test/src/main.cpp.o
CMakeFiles/matrix1_testCuda_gtest.dir/cmake_device_link.o -o
matrix1_testCuda_gtest ../implementation/libmatrix1_testCuda_core.a
/usr/lib/libgtest.a /usr/lib/libgtest_main.a
I got this to work by calling
find_package(CUDA 9.0 REQUIRED)
in both CMake files.
Also, in the Algo file (which contains the device code), I had to do
target_link_libraries(${PROJECT_NAME} ${CUDA_LIBRARIES})
I was expecting that the language support for CUDA would make those steps unnecessary, but apparently not.
I just ran into something very similar to this where the root problem was that most of my binary was being compiled with my system cxx compiler, and the cuda bits were being compiled with the cuda gcc compiler (9.1 for system, 8.3 for cuda).
Surprisingly it was fixed by changing:
project(MyProject LANGUAGES CXX CUDA)
to
project(MyProject LANGUAGES CUDA CXX)
After that change, CMake picked up the cuda version of the gcc compiler as the main compiler, and my binary started building again. I'm not sure if this could introduce problems for other packages, but it fixed the linking problem I was hitting.
Adding the possible way in CMake 3.18 and further
When you wish not to include any CUDA code, but e.g. using only calls to cufft from C++ it is sufficient to do the following
find_package(CUDAToolkit)
target_link_libraries(project CUDA::cudart)
target_link_libraries(project CUDA::cufft)
If you are however enabling CUDA support, unless you want to get into troubles call it after enabling CUDA.
include(CheckLanguage)
check_language(CUDA)
if(CMAKE_CUDA_COMPILER)
enable_language(CUDA)
find_package(CUDAToolkit)
target_link_libraries(project CUDA::cudart)
target_link_libraries(project CUDA::cuda_driver)
else()
message(STATUS "No CUDA compiler found")
endif()
Because CUDAToolkit respects enable CUDA runtime added but it does not work vice versa.

Static linking DCMTK library

I use DCMTK in my application and for compilation use cmake file. cmake finds all libraries (at least headers, because in compiles source files to .o files) the only problem is that during linking it tries to find dynamic libraries for DCMTK. I compiled one as static, so I do not have .so files. As a result it gives me error :No rule to make target /usr/lib/libdcmdata.so, needed by dcm_seg. Stop.
I use Ubuntu 14.04 x64.
It confuses me pretty much. So, what's the problems?
cmake file:
cmake_minimum_required(VERSION 2.6)
project(dcm_segm)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
set(Boost_USE_STATIC_LIBS ON)
set(OpenCV_USE_STATIC_LIBS ON)
set(DCMTK_USE_STATIC_LIBS ON)
set(OpenCV_STATIC ON)
find_package( VTK REQUIRED )
find_package( OpenCV REQUIRED )
find_package( Boost COMPONENTS system filesystem REQUIRED )
find_package( DCMTK REQUIRED )
include(${VTK_USE_FILE} )
link_directories(${OpenCV_LIB_DIR})
add_executable(dcm_seg main.cpp DICOMin.cpp Ensemble.cpp Ensemble3dExtension.cpp point_3d.cpp RegionGrow.cpp)
target_link_libraries(dcm_seg ${VTK_LIBRARIES} ${OpenCV_LIBS} ${DCMTK_LIBRARIES} ${Boost_LIBRARIES})
Can you check the content of ${DCMTK_LIBRARIES} (it should be a list of paths to DCMTK static libraries) ?
you can also check the following CMake entries during the CMake configuration:
DCMTK_DIR /path/to/DCMTK/install
DCMTK_config_INCLUDE_DIR /path/to/DCMTK/install/include/dcmtk/config
DCMTK_dcmdata_INCLUDE_DIR /path/to/DCMTK/install/dcmdata/include/dcmtk/dcmdata
DCMTK_dcmdata_LIBRARY_DEBUG /path/to/DCMTK/install/dcmdata/libsrc/libdcmdata.a
DCMTK_dcmdata_LIBRARY_RELEASE /path/to/DCMTK/install/dcmdata/libsrc/libdcmdata.a
[...]
Another hint: I noted in the past that find DCMTK from a build instead of an install not always works properly.
If you have trouble finding DCMTK with the script provided with CMake
(${DCMTK_LIBRARIES} doesn not content the path to you static DCMTK libs for example) you can try to use this alternative script

CMake third party library undefined reference

I already read and searched a lot (e.g. 1 2 3, several docs for CMake, similar projects, etc. to find a solution but I have not been able to solve my problem. I am relatively new to Cmake and Linux (Ubuntu 14.04).
I want to use libsbp (https://github.com/swift-nav/libsbp) to write a program in C++ to communicate with a GPS module. I cloned the repository and installed the C-Library. So now in /usr/local/lib there are two files: libsbp.so and libsbp-static.a and the headers are in /usr/local/include/libsbp
In my own project I include the headers with #include "libsbp/sbp.h" which also works.
Now the Problem: if I want to use a method from libsbp e.g. sbp_state_init(&s); I get undefined reference to "sbp_state_init(sbp_state_t*)"
The relevant part of my Cmake for my own project:
link_directories(/usr/local/lib)
add_executable(main ${QT_SOURCES} ${QT_HEADER_HPP})
target_link_libraries(main ${QT_LIBRARIES} ${catkin_LIBRARIES} sbp)
As I said before, I tried some things:
find_library(SBP_LIB sbp /usr/local/lib) -> same error
same goes for using libsbp in target_link_libraries or searching for it
link_directory(/usr/local/lib)
trying different paths, even moveing libsbp.so into the project directory and "finding" it with ${CMAKE_CURRENT_SOURCE_DIR}
Maybe you can help me!
edit:
this is the CMakeList.txt from the libsbp/c/src directory
if (NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON)
endif (NOT DEFINED BUILD_SHARED_LIBS)
file(GLOB libsbp_HEADERS "${PROJECT_SOURCE_DIR}/include/libsbp/*.h")
include_directories("${PROJECT_SOURCE_DIR}/CBLAS/include")
include_directories("${PROJECT_SOURCE_DIR}/clapack-3.2.1-CMAKE/INCLUDE")
include_directories("${PROJECT_SOURCE_DIR}/lapacke/include")
include_directories("${PROJECT_SOURCE_DIR}/include/libsbp")
set(libsbp_SRCS
edc.c
sbp.c
)
add_library(sbp-static STATIC ${libsbp_SRCS})
install(TARGETS sbp-static DESTINATION lib${LIB_SUFFIX})
if(BUILD_SHARED_LIBS)
add_library(sbp SHARED ${libsbp_SRCS})
install(TARGETS sbp DESTINATION lib${LIB_SUFFIX})
else(BUILD_SHARED_LIBS)
message(STATUS "Not building shared libraries")
endif(BUILD_SHARED_LIBS)
install(FILES ${libsbp_HEADERS} DESTINATION include/libsbp)
this is the CMakeList.txt from /libsbp/c/
cmake_minimum_required(VERSION 2.8.9)
project(libsbp)
# Setup flags for Code Coverage build mode
set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used by the C++ compiler for building with code coverage."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used by the C compiler for building with code coverage."
FORCE )
SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
"${CMAKE_EXE_LINKER_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used for linking binaries with code coverage."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} --coverage" CACHE STRING
"Flags used by the shared libraries linker during builds with code coverage."
FORCE )
mark_as_advanced(
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
# Update the documentation string of CMAKE_BUILD_TYPE for GUIs
set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage."
FORCE )
# Set project version using Git tag and hash.
execute_process(
COMMAND git describe --dirty --tags --always
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE GIT_VERSION_FOUND
ERROR_QUIET
OUTPUT_VARIABLE GIT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (GIT_VERSION_FOUND)
set(VERSION "unknown")
else (GIT_VERSION_FOUND)
set(VERSION ${GIT_VERSION})
endif (GIT_VERSION_FOUND)
# Set project version explicitly for release tarballs.
#set(VERSION foo)
message(STATUS "libsbp version: ${VERSION}")
cmake_minimum_required(VERSION 2.8)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Some compiler options used globally
set(CMAKE_C_FLAGS "-Wall -Wextra -Wno-strict-prototypes -Wno-unknown-warning-option -Werror -std=gnu99 ${CMAKE_C_FLAGS}")
add_subdirectory(src)
add_subdirectory(docs)
add_subdirectory(test)
It seems that your program uses C++ and the library is written in C.
Symbols in C and C++ are encoded differently (mangled). When including C headers from C++ you need to tell the compiler. This can be done by declaring the symbols extern "C".
extern "C" {
#include <libsbp/sbp.h>
}
Some libraries already include this in their headers, but not sbp.
You have (at least) two possibilities:
Installing the library (this is what you did)
Integrating the library in your CMake project
When installing the library, the target_link_libraries command needs to be modified slightly:
find_library(SBP_LIB sbp /usr/local/lib)
target_link_libraries(main ${QT_LIBRARIES} ${catkin_LIBRARIES} ${SBP_LIB})
When you integrate the library in your CMake project, you can directly use the following command without using find_library. This works, because the library is known to CMake since it is built within the current project.
target_link_libraries(main ${QT_LIBRARIES} ${catkin_LIBRARIES} sbp)

How to link google protobuf libraries via cmake on linux?

I'm trying to make it same way I made it for boost :
find_package(Boost COMPONENTS system filesystem REQUIRED)
find_package(ProtocolBuffers)
## Compiler flags
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-O2")
set(CMAKE_EXE_LINKER_FLAGS "-lsqlite3 -lrt -lpthread")
endif()
target_link_libraries(complex
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${PROTOBUF_LIBRARY}
)
(googled it somewhere) but got bad output:
CMake Warning at complex/CMakeLists.txt:18 (find_package):
Could not find module FindProtocolBuffers.cmake or a configuration file for
package ProtocolBuffers.
Adjust CMAKE_MODULE_PATH to find FindProtocolBuffers.cmake or set
ProtocolBuffers_DIR to the directory containing a CMake configuration file
for ProtocolBuffers. The file will have one of the following names:
ProtocolBuffersConfig.cmake
protocolbuffers-config.cmake
How can I link it with cmake? or maybe I even can compile .proto file using cmake?
You could try CMake's FindProtobuf module:
include(FindProtobuf)
find_package(Protobuf REQUIRED)
include_directories(${PROTOBUF_INCLUDE_DIR})
...
target_link_libraries(complex
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${PROTOBUF_LIBRARY}
)
For further info, run
cmake --help-module FindProtobuf
Spent a lot of time on this..
A. Different versions may require regeneration of cc files (obviously)
B. Different versions have different naming (PROTOBUF_LIBRARY vs. Protobuf_LIBRARIES)
Do note that the previous answer refers to view the FindProtobuf help which states the naming convention.
Also, Use '''message(STATUS "debug protobuf lib location:${PROTOBUF_LIBRARIES} '''
to debug.