Finding the nVIDIA Toolkit Extensions library with CMake - cmake

I'm using CMake 3.13, with inherent support for CUDA as a language, to build a project. This project requires the nVIDIA Toolkit Extensions library. On a previous system, I had it under /usr/local/cuda/lib64. I used a find_library() command which I thought should be sufficient, and all was well. But - it isn't, and it wasn't: On a system in which CUDA is installed using OS distribution packages, under /usr directly, my command doesn't work.
To be more specific, I'm using:
find_library(CUDA_NVTX_LIBRARY
NAMES nvToolsExt nvTools nvtoolsext nvtools nvtx NVTX
PATHS ${CUDA_TOOLKIT_ROOT_DIR} ENV LD_LIBRARY_PATH
PATH_SUFFIXES "lib64" "common/lib64" "common/lib" "lib"
DOC "Location of the CUDA Toolkit Extension (NVTX) library"
NO_DEFAULT_PATH
)
and this is missing /usr/lib/x86_64-linux-gnu/libnvToolsExt.so.
Questions:
How should I alter my find_library command not to miss such target-platform-specific folders?
Am I looking for the NVTX library the wrong way? Can I somehow rely on what CMake finds internally instead?
Notes:
I have basically the same issue with libOpenCL.so, nVIDIA's OpenCL layer.

(This answer regards CMake versions earlier than 3.17; you should really switch to a newer version of CMake, which makes your life much easier.)
CMake does figure out the paths of a lot of other CUDA-related libraries, e.g.:
CUDA_CUDART_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcudart.so
CUDA_CUDA_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcuda.so
CUDA_cublas_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcublas.so
CUDA_cudadevrt_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcudadevrt.a
CUDA_cudart_static_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcudart_static.a
CUDA_cufft_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcufft.so
CUDA_cupti_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcupti.so
CUDA_curand_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcurand.so
CUDA_cusolver_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcusolver.so
CUDA_cusparse_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libcusparse.so
CUDA_nppc_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppc.so
CUDA_nppial_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppial.so
CUDA_nppicc_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppicc.so
CUDA_nppicom_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppicom.so
CUDA_nppidei_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppidei.so
CUDA_nppif_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppif.so
CUDA_nppig_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppig.so
CUDA_nppim_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppim.so
CUDA_nppist_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppist.so
CUDA_nppisu_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppisu.so
CUDA_nppitc_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnppitc.so
CUDA_npps_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libnpps.so
CUDA_rt_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/librt.so
I think it's actually a bug that it doesn't do so for the NVTX and OpenCL libraries. Still, we can take the paths it finds for other libraries - perhaps the main one, CUDA_CUDART_LIBRARY, and use it as a search hint.
The result is even uglier than what I had before, but it does seems to work:
get_filename_component(CUDA_CUDART_LIBRARY_DIR "${CUDA_CUDART_LIBRARY}" PATH CACHE)
find_library(CUDA_OPENCL_LIBRARY
NAMES OpenCL opencl
PATHS "${CUDA_CUDART_LIBRARY_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}" ENV LD_LIBRARY_PATH
PATH_SUFFIXES "lib64" "lib"
DOC "Location of the CUDA OpenCL support library"
NO_DEFAULT_PATH
)
find_library(CUDA_NVTX_LIBRARY
NAMES nvToolsExt nvTools nvtoolsext nvtools nvtx NVTX
PATHS "${CUDA_CUDART_LIBRARY_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}" ENV LD_LIBRARY_PATH
PATH_SUFFIXES "lib64" "common/lib64" "common/lib" "lib"
DOC "Location of the CUDA Toolkit Extension (NVTX) library"
NO_DEFAULT_PATH
)

You may try CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES (suggested here), which worked for me:
project(theproject LANGUAGES CUDA)
find_library(LIBNVTOOLSEXT nvToolsExt PATHS ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES})

Related

How to tell cmake to look for Boost headers in a specified location?

I am using Boost libraries for my cmake C++ project:
find_package(Boost REQUIRED system)
Which correctly sets the Boost_INCLUDE_DIRS variable to my local Boost installation /usr/local/inlude
After I installed miniconda, which has its own boost installation, my project now looks for boost headers in
/usr/share/miniconda3/include/boost
How do I tell cmake not too look for boost headers in miniconda directories and use /usr/local/include instead?
If the two Boost library with a different version number, you can specify the Version Number in find_package cmd, like this:
find_package(Boost 1.62.0 ...)
In addtion, if /usr/share/miniconda3/include/boost is not in your cmake search path, you may need:
set(CMAKE_PREFIX_PATH /usr/share/miniconda3/include/boost)

How to choose OpenCL implementation with CMake?

I have a Windows OpenCL application that uses some of the AMD extensions. Additionally, my application has some optional CUDA components. When building the visual studio solution with CMake, the FindOpenCL module picks the Nvidia OpenCL implementation instead of AMD's. Is there an easy way to make CMake use the AMD version?
I tried commenting the Nvidia sections in the FindOpenCL module code, but that did not work. Is there some registry setting I can modify? I installed CUDA after installing AMD's SDK. Would the installation order make a difference?
In the end, what worked was to remove the NVIDIA environment variables from the PATHS suggestions in the find_library and find_path commands and adding the NO_DEFAULT_PATH. The issue was that, even though I removed the suggestions, CMake was adding the default path which included NVIDIA's OpenCL implementation. Both commands ended up like shown below:
find_path(OpenCL_INCLUDE_DIR
NAMES
CL/cl.h OpenCL/cl.h
NO_DEFAULT_PATH
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
include
OpenCL/common/inc
"AMD APP/include")
find_library(OpenCL_LIBRARY
NAMES OpenCL
NO_DEFAULT_PATH
PATHS
ENV "PROGRAMFILES(X86)"
ENV AMDAPPSDKROOT
ENV ATISTREAMSDKROOT
PATH_SUFFIXES
"AMD APP/lib/x86_64"
lib/x86_64
lib/x64
OpenCL/common/lib/x64)

What's the difference between CMAKE_INSTALL_PREFIX and CMAKE_INSTALL_RPATH

I have a difficult time in understanding the difference between CMAKE_INSTALL_PREFIX and CMAKE_INSTALL_RPATH.
If I understand well, CMAKE_INSTALL_PREFIX is the prefixed directory that will be installed. Therefore, if I use the following script for installation:
project(hello)
add_library(hello hello.h hello.cpp)
set(CMAKE_INSTALL_PREFIX "c:/ABC/DEF")
INSTALL(TARGETS hello EXPORT hello_export
RUNTIME DESTINATION bin
LIBRARY DESTINATION bin
ARCHIVE DESTINATION lib
FRAMEWORK DESTINATION bin
INCLUDES DESTINATION include
)
Then the static library will be installed in C:/ABC/DEF/lib.
Then, my question is what's the point of using CMAKE_INSTALL_RPATH?
On a system which supports paths of the form c:/ABC/DEF (i.e. Windows), none. Windows binaries don't have a notion of rpath.
On systems which do have DT_RPATH and DT_RUNPATH (= those which use ELF binaries), the CMake variable CMAKE_INSTALL_RPATH is used to set up the value of DT_RPATH (or DT_RUNPATH) tags which will be written into the binaries at installation.
This is explained at CMake RPATH handling.
On Unix systems, dynamic libraries are searched for in a system-defined list of directories. (/etc/ld.so.conf -- Windows does this in its own way that is so convoluted that it usually boils down to "just use PATH". 😉)
If you install a library (like the one you just compiled) in a custom directory, not in that list, it will not be found if you run a dependent executable. RPATH is one way to fix this.
See the Wiki page linked above for details.
Firstly, CMAKE_INSTALL_PREFIX determines a "root" for the installed location of headers, libraries, executables, and other resources.
On a system which does not support the notion of a "search hierachy" for dependencies, CMAKE_INSTALL_RPATH is not used. However, on ELF-based systems (e.g. Linux) and Mach-based systems (e.g. macOS 10.5 and later) a set of additional locations to search can be set in executables and dynamic libraries (e.g. .so/.dylib files); this is the "Rpath" and you can set it during cmake's install phase, either for all targets by setting CMAKE_INSTALL_RPATH or for individual targets by setting INSTALL_RPATH on that target.
Static libraries are not dynamic (obviously!) so, CMAKE_INSTALL_RPATH has no utility at all for static libraries.
When installing dynamic objects, CMake will write the Rpath into the dynamic object provided CMAKE_SKIP_RPATH and CMAKE_SKIP_INSTALL_RPATH are both false. By default, the Rpath written will be set to CMAKE_INSTALL_PREFIX followed by the library destination, e.g. CMAKE_INSTALL_PREFIX/lib. On Linux systems, this would by default see an Rpath of /usr/local/lib written as Rpath.
You can examine the Rpath on Linux thus:
readelf -d libmylib.so
which produces something like:
0x000000000000000f (RPATH) Library rpath: [/usr/local/lib]
or on macOS:
otool -l libmylib.dylib | grep -A 2 LC_RPATH
which produces something like:
cmd LC_RPATH
cmdsize 40
path #loader_path/../Frameworks (offset 12)
To override the install Rpath you can set the variable CMAKE_INSTALL_RPATH. E.g. on Linux:
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib")
or on macOS:
set(CMAKE_INSTALL_RPATH "#loader_path/../lib")

Linking against GLEW with CMake

My project depends on GLEW and is built with CMake, so i took the FindGLEW.cmake from here http://code.google.com/p/nvidia-texture-tools/source/browse/trunk/cmake/FindGLEW.cmake?r=96 and wrote find_package(GLEW REQUIRED) in my CMakeLists.txt. Problem is that i am working on a cluster PC were several versions of GLEW are available. One version is stored in /usr/lib which is not the latest. the latest version is stored in /opt/local/lib64. this is the version i want to link against. so i added the path to the FindGLEW.cmake under the GLEW_LIBRARY paths. the problem is that the makefile always links against the older version, but i need the newest version (1.7) for using stuff like GL_PATCHES, GL_PATCH_PARAMETERS and so on. can i some how force CMake to use the newer version like it is the case with FindBoost.cmake. one solution is to erase the older one's but this is not an option. i also changed the order of the paths in the GLEW_LIBRARY list, but without success.
in my old Makefile i just wrote LDDFLAGS = -L/opt/local/lib64 -lGLEW so the path is absolutely clear, but now with CMake i want to use the find feature, but want to prefer a specific version.
I use this to link statically to a custom compiled GLEW lib at a specific location:
#GLEW libraries
add_library(glew_static STATIC IMPORTED)
set_target_properties(glew_static PROPERTIES
IMPORTED_LOCATION /home/ryan/DevLibrary/glew-1.9.0/lib/libGLEW.a)
target_link_libraries(smolder glew_static)
With this in place you can remove
find_package(GLEW REQUIRED)
You can use this with shared libraries as well, simply remove the STATIC keyword from add_library.

How to cross compile CMake for ARM with CMake

In short I'm trying to cross compile CMake with CMake, and I don't think I'm linking libraries correctly. What I want to do may not be possible, but I'd at least like to know why it isn't possible if that's the case.
System: The host is a Linux box with a Cavium ARM9 CPU. It's currently running version 2.6.24.4 of the Linux kernel and Debian 5.0 (Lenny). My workstation is a Core i5 running Ubuntu 12.04 LTS (Precise Pangolin).
My overall goal is to get ROS running on the Linux box. I have to compile from source rather than use apt since Debian 6.0 (Squeeze) binaries require thumb support that the Cavium does not give, and not many of the needed packages are available for Debian 5.0 (Lenny). I'd made progress installing the various libraries needed, but when I got to step 1.3.1 and tried to run CMake, I got the error
CMake 2.8 or higher is required. You are running version 2.6.0
Next I tried to download and build CMake 2.8.8 on the Linux box itself, but it was too much for the system. When that failed, I downloaded the toolchain suggested on the manufacturer's website and used the cross-compiling guide at [www.cmake.org/Wiki/CMake_Cross_Compiling] to build the CMake executables. Here is my toolchain file:
# This one is important
SET(CMAKE_SYSTEM_NAME Linux)
# Specify the cross compiler
SET(CMAKE_C_COMPILER /pathto/crosstool-linux-gcc-4.5.2-gclibc-2.9-oabi/arm-unknown-linux-gnu/bin/arm-unknown-linux-gnu-gcc)
SET(CMAKE_CXX_COMPILER /pathto/crosstool-linux-gcc-4.5.2-gclibc-2.9-oabi/arm-unknown-linux-gnu/bin/arm-unknown-linux-gnu-g++)
# Where is the target environment
SET(CMAKE_FIND_ROOT_PATH /pathto/crosstool-linux-gcc-4.5.2-gclibc-2.9-oabi/arm-unknown-linux-gnu /pathto/crosstool-linux-gcc-4.5.2-gclibc-2.9-oabi/arm-unknown-linux-gnu/arm-unknown-linux-gnu)
# Search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
However, use of the binary on the Linux box gives the error
cmake: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by cmake)
Sure enough, the library is not there:
prompt# strings /usr/lib/libstdc++.so.6 | grep GLIBC
GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBC_2.3
GLIBC_2.0
GLIBC_2.3.2
GLIBC_2.1
GLIBC_2.1.3
GLIBC_2.2
GLIBCXX_FORCE_NEW
GLIBCXX_DEBUG_MESSAGE_LENGTH
I've never cross-compiled before, but I can see one of two scenarios happening: either the binary got created with a link to a higher version of glibcxx on the host machine or the manufacturer's toolchain is more modern than their image. I don't know how to check which is happening or if something else is happening that I don't know about.
My last effort involved trying to statically cross-compile CMake to hopefully get rid of the linking error with
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-technologic.cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS_RELEASE="-static" ..
I got build errors, and that binary didn't work either. I got:
FATAL: kernel too old
Segmentation fault
I'd try installing glibcxx 3.4.14 on the Linux box, but it doesn't look like it's available for this processor.
I've tried searching for CMake dependencies or system requirements and can't find anything. I've also searched on how to build CMake, but most searches turn up how to build other things with CMake rather than building CMake itself.
I do cross-compile a lot for ARM9 devices using CMake, and indeed this looks like you're not linking to the same libs you have on your target device. You shouldn't need to build CMake yourself to get this done, since it does have good support for cross-compiling since version 2.6. Just make sure you set the CMAKE_FIND_ROOT_PATH variable to a path where you have an exact copy of the root filesystem you have on your target device (with libraries and binaries pre-compiled for the target processor). That should solve your problems.
As a sidenote, I like to use crosstool-ng for building my cross-compilers. It is a really nice tool which helps you to build them from scratch, so I try to match the compiler version and glibc to the ones originally used to build the root filesystem (I usually start with a ready made root filesystem from ARMedslack, since I use Slackware for my development box and ARMedslack for my ARM targets).