Cuda CMake 3.10 CMakeLists.txt - cmake

I have a visual c++ project which creates a dll.
For this project I have a working CMakeLists.txt.
Now I created two cuda source files which complete the project and
with visual studio the build works fine.
I want to add the matching commands to my cmake file.
Can anyone tell me the basic commands I need to add?
I try to build a dll library where i use .cu and .cpp files....
The important part of my cmake file looks like:
# ----------------------------------------------------------------------------
# Set Cuda properties
# ----------------------------------------------------------------------------
enable_language(CUDA)
set(CUDA_SEPARABLE_COMPILATION ON)
set(CUDA_PROPAGATE_HOST_FLAGS OFF)
if (CMAKE_SIZEOF_VOID_P MATCHES 8)
set(CUDA_64_BIT_DEVICE_CODE_DEFAULT ON)
endif()
set(CUDA_NVCC_FLAGS "-gencode arch=compute_50,code=sm_50;-rdc=true;-use_fast_math")
message(STATUS "CUDA_PROPAGATE_HOST_FLAGS: ${CUDA_PROPAGATE_HOST_FLAGS}")
message(STATUS "CUDA_HOST_COMPILER: ${CUDA_HOST_COMPILER}")
message(STATUS "CUDA_NVCC_FLAGS: ${CUDA_NVCC_FLAGS}")
# ----------------------------------------------------------------------------
# Create shared library project
# ----------------------------------------------------------------------------
add_library(${LIB_NAME} SHARED ${HEADERS} ${SOURCES} ${CUDA_SOURCES})
set(CUDA_LIBRARIES "cudadevrt.lib;cudart.lib")
target_link_libraries(${LIB_NAME} ${CUDA_LIBRARIES})
But it doesn't compile the cuda files with the right flags.
Also in visual studio the preprocessor definitions are also in the cuda part of the properties....any suggestions?

I'll try to answer this question using the discussion from the comments and add some extra information.
First of all, there are two ways to enable CUDA support in CMake. One is the old FindCUDA module, and the other is the new built-in CUDA language support added in CMake 3.8, and explained here.
You can choose one or the other (but you'll probably want to use the built-in support for new projects), but then you have to stick with your choice.
To use built-in support you either add it to the project(...) statement or use:
enable_language(CUDA);
To use the old FindCUDA package, you would use:
find_package(CUDA);
Note that the two options use completely different variables for setup. To see what variables are supported by FindCUDA see this page, and for built-in CUDA support see this (don't forget that the <LANG> placeholder can be replaced by any language, which means that CUDA is also one of the available substitutions).
E.g. with FindCUDA you would use CUDA_NVCC_FLAGS to set the compiler flags manually, and with built-in language support you would use CMAKE_CUDA_FLAGS for the same purpose. As a rule of thumb: if the variable starts with CUDA_ it is a part of the FindCUDA package, and if it starts with CMAKE_, then it is part of built-in support.

Related

CMake GET_RUNTIME_DEPENDENCIES couldn't find dll library when it is linked through lib (import library)?

Build OS: Windows 10, Cmake 3.16.3.
I use target_link_libraries to link 3rd party .lib file to my .dll library.
But when I use GET_RUNTIME_DEPENDENCIES to install my dll, there is no dependency found.
It happens only on Windows, installing on Linux is ok.
Is there any clues how to solve this problem, or at least how to debug it?
What exact command uses CMake on Windows to determine dependencies?
I call GET_RUNTIME_DEPENDENCIES like this:
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES ${EXECS}
LIBRARIES ${LIBS} ${MODULES} ${QTPLUGINS_LIBS}
DIRECTORIES ${RUNTIME_DEPENDENCIES_DIRECTORIES}
POST_EXCLUDE_REGEXES ${PLATFORM_POST_EXCLUDE_REGEXES}
)
Where LIBS contains my dll but no RES no UNRES contains path to 3rd paty dll.
So, there's a serious nastiness to all this runtime-dependency-finding magic in the newer CMakes, and it's not really their fault at all. The problem is that you, I, and roughly 90% of the rest of the CMake user world have been doing find modules wrong #THISWHOLETIME, and now our chickens have come home to roost because, as you've likely discovered, GET_RUNTIME_DEPENDENCIES / RUNTIME_DEPENDENCY_SET, $<TARGET_RUNTIME_DLLS> will all completely sh*t the bed if you try to use them with targets that have (what I now know to be) broken IMPORTED dependencies created by Find modules that don't properly set them up. So, last month I posted this screed (my earlier link) over at the CMake Discourse forum:
Windows libraries, Find modules, and TARGET_RUNTIME_DLLS
The Windows DLL Question™ has come up numerous times before in one form or another, but it’s cast in a new light by $<TARGET_RUNTIME_DLLS>, so here’s a fresh take on it.
If you’re like me (and roughly 90% of all CMake users/developers out there are like me, from what I’ve been able to observe in public projects’ source trees), your approach to writing Find modules on Windows has probably been something like this:
Use the same code on all three desktop platforms
Let CMake discover .lib / .dll.a import libraries instead of actual DLLs, using find_library().
End up creating your targets as UNKNOWN IMPORTED, because if you try to create SHARED IMPORTED library targets with only an import library it won’t work, but UNKNOWN IMPORTED works just fine so meh.
Set the import library as the target’s IMPORTED_LOCATION since that seems to work fine.
Call it a day, because hey — everything compiles.
That’s served us all for years (decades, really) so we’ve mostly just accepted it as the way CMake works on Windows.
But now along comes $<TARGET_RUNTIME_DLLS>. If you’ve tried to actually use it on Windows, you’ve probably discovered is that while all of your CONFIG-mode package dependencies’ DLLs are captured just fine, the generator expression will cheerfully ignore any targets created from a Find module that’s written like I describe above. …Which is probably most of them. (In my own library build, it was all of them, even the ones I didn’t write.)
For $<TARGET_RUNTIME_DLLS> to work, the IMPORTED target has to be correctly defined as a SHARED library target, and it needs to have its IMPORTED_ properties set correctly: import lib path in IMPORTED_IMPLIB, DLL path in IMPORTED_LOCATION.
So, now I have this new module that uses DLLTOOL.EXE and its handy -I flag to get the name of an import library’s DLL, then looks it up using find_program(). (Simply because find_library() won’t match DLLs, and I wanted to look on the PATH. I could’ve used find_file() but I’m pretty sure I’d have to explicitly give it more paths to search.)
The macro takes one argument, the name of your already-configured variable <prefix>_IMPLIB. (Or <prefix>_IMPLIBS, it’s pluralization agnostic and will follow whichever form your input uses when naming its output variable.)
The variable whose name you pass to it should already contain a valid path for an import library. Typically that’s set by find_library(), even though we’ve all been treating them like runtime libraries (DLLs) when they are not.
Armed with find_library(<prefix>_IMPLIB ...) output, implib_to_dll(<prefix>_IMPLIB) will attempt to discover and automatically populate the corresponding variable <prefix>_LIBRARY with the path to the import lib’s associated runtime DLL.
With all of the correct variables set to the correct values, it’s now possible to properly configure SHARED IMPORTED library targets on Windows. $<TARGET_RUNTIME_DLLS> can then be used to discover and operate on the set of DLLs defined by those target(s).
Kind of a pain in the Find, and really does sort of feel like something CMake could be doing at-least-semi-automatically. But, at least for now it works.
Now I just have to rewrite all of my find modules to use it. Sigh.
ImplibUtils.cmake
#[=======================================================================[.rst:
IMPLIB_UTILS
------------
Tools for CMake on WIN32 to associate IMPORTED_IMPLIB paths (as discovered
by the :command:`find_library` command) with their IMPORTED_LOCATION DLLs.
Writing Find modules that create ``SHARED IMPORTED`` targets with the
correct ``IMPORTED_IMPLIB`` and ``IMPORTED_LOCATION`` properties is a
requirement for ``$<TARGET_RUNTIME_DLLS>`` to work correctly. (Probably
``IMPORTED_RUNTIME_DEPENDENCIES`` as well.)
Macros Provided
^^^^^^^^^^^^^^^
Currently the only tool here is ``implib_to_dll``. It takes a single
argument, the __name__ (_not_ value!) of a prefixed ``<prefix>_IMPLIB``
variable (containing the path to a ``.lib`` or ``.dll.a`` import library).
``implib_to_dll`` will attempt to locate the corresponding ``.dll`` file
for that import library, and set the variable ``<prefix>_LIBRARY``
to its location.
``implib_to_dll`` relies on the ``dlltool.exe`` utility. The path can
be set by defining ``DLLTOOL_EXECUTABLE`` in the cache prior to
including this module, if it is not set implib_utils will attempt to locate
``dlltool.exe`` using ``find_program()``.
Revision history
^^^^^^^^^^^^^^^^
2021-11-18 - Updated docs to remove CACHE mentions, fixed formatting
2021-10-14 - Initial version
Author: FeRD (Frank Dana) <ferdnyc#gmail.com>
License: CC0-1.0 (Creative Commons Universal Public Domain Dedication)
#]=======================================================================]
include_guard(DIRECTORY)
if (NOT WIN32)
# Nothing to do here!
return()
endif()
if (NOT DEFINED DLLTOOL_EXECUTABLE)
find_program(DLLTOOL_EXECUTABLE
NAMES dlltool dlltool.exe
DOC "The path to the DLLTOOL utility"
)
if (DLLTOOL_EXECUTABLE STREQUAL "DLLTOOL_EXECUTABLE-NOTFOUND")
message(WARNING "DLLTOOL not available, cannot continue")
return()
endif()
message(DEBUG "Found dlltool at ${DLLTOOL_EXECUTABLE}")
endif()
#
### Macro: implib_to_dll
#
# (Win32 only)
# Uses dlltool.exe to find the name of the dll associated with the
# supplied import library.
macro(implib_to_dll _implib_var)
set(_implib ${${_implib_var}})
set(_library_var "${_implib_var}")
# Automatically update the name, assuming it's in the correct format
string(REGEX REPLACE
[[_IMPLIBS$]] [[_LIBRARIES]]
_library_var "${_library_var}")
string(REGEX REPLACE
[[_IMPLIB$]] [[_LIBRARY]]
_library_var "${_library_var}")
# We can't use the input variable name without blowing away the
# previously-discovered contents, so that's a non-starter
if ("${_implib_var}" STREQUAL "${_library_var}")
message(ERROR "Name collision! You probably didn't pass "
"implib_to_dll() a correctly-formatted variable name. "
"Only <prefix>_IMPLIB or <prefix>_IMPLIBS is supported.")
return()
endif()
if(EXISTS "${_implib}")
message(DEBUG "Looking up dll name for import library ${_implib}")
execute_process(COMMAND
"${DLLTOOL_EXECUTABLE}" -I "${_implib}"
OUTPUT_VARIABLE _dll_name
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(DEBUG "DLLTOOL returned ${_dll_name}, finding...")
# Check the directory where the import lib is found
get_filename_component(_implib_dir ".." REALPATH
BASE_DIR "${_implib}")
message(DEBUG "Checking import lib directory ${_implib_dir}")
# Add a check in ../../bin/, relative to the import library
get_filename_component(_bindir "../../bin" REALPATH
BASE_DIR "${_implib}")
message(DEBUG "Also checking ${_bindir}")
find_program(${_library_var}
NAMES ${_dll_name}
HINTS
${_bindir}
${_implib_dir}
PATHS
ENV PATH
)
set(${_library_var} "${${_library_var}}" PARENT_SCOPE)
message(DEBUG "Set ${_library_var} to ${${_library_var}}")
endif()
endmacro()
GET_RUNTIME_DEPENDENCIES isn't aware of your configure-time variables, so will you need to specify them manually. This answer states you can pass-on the variables to the install step, but I haven't been able to make it work so far. Fortunately, it does support generator expressions.
Another problem in your snippet is it must be called at install time. For example in an install(CODE ...) block.
So with all this in mind, this should get you started.
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:your_executable_target_name>
LIBRARIES $<TARGET_FILE:a_lib_target_name>
)
message("\n\nFound dependencies :")
foreach(DEP ${RES})
message("${DEP}")
endforeach()
message("\n\nNot found dependencies :")
foreach(DEP ${UNRES})
message("${DEP}")
endforeach()
]])
Build your install target to see the results.
cmake ..
cmake --build . --target install

Create dynamic library that implements multiple LLVM passes

I have a static library, which consists of several passes and is a part of opt. I want to make it dynamic and create one dylib file, so I could call opt, loading created .dylib and passing the desired LLVM pass. I'm using LLVM 7.0.
I created such dylib file with the help of Xcode (by adding to already existing dynamic library target additional passes), but I can't find any information, how to make it with the help of CMake.
At the moment, CMake file of the library looks like this:
add_llvm_library(MyLibrary
Pass1.cpp
Pass2.cpp
Pass3.cpp
...
PassN.cpp
DEPENDS
intrinsics_gen
)
What is expected is performing such command:
path/to/opt -load /path/to/MyLibrary.dylib -Pass3 ...
It isn't clear to me, whether it is possible to leave the structure of the library as is or if I have to modify it, by giving each pass a CMakeLists.txt file.
Tried this, faced up to the problem of multiple dependencies, which required to include several libraries. Linked libraries required required another libraries being linked. After a while, took a Hello CMakeLists.txt, which was provided in LLVM, as an example. Instead of add_llvm_library, wrote add_llvm_loadablemodule, making such CMakeLists.txt
if (WIN32 OR CYGWIN)
set(LLVM_LINK_COMPONENTS ...)
endif()
add_llvm_loadable_module(Mylib_Dylib
Pass1.cpp
Pass2.cpp
...
PassN.cpp
PLUGIN_TOOL
opt
)
It build Mylib.dylib, and it was possible to call a pass from it.
Since LLVM 8.0 the add_llvm_loadable_module CMake directive has been removed from LLVM. It has been replaced with using add_llvm_library with the MODULE argument.
if (WIN32 OR CYGWIN)
set(LLVM_LINK_COMPONENTS ...)
endif()
add_llvm_library(Mylib_Dylib MODULE
Pass1.cpp
Pass2.cpp
...
PassN.cpp
PLUGIN_TOOL
opt
)

Directing cmake to link against shared object with debug postfix (_d)

I've got a cmake project that pretty much looks like this:
cmake_minimum_required(VERSION 3.0)
SET(CMAKE_DEBUG_POSTFIX "_d")
include_directories(../TransfunctionerProject)
include_directories(../TransmogrifierProject)
set(Libraries
ContinuumTransfunctioner
Transmogrifier
)
set(SourceFiles
Wrapper.cpp
Logger.cpp
)
add_library(Frobnigator SHARED ${SourceFiles})
add_library(FrobnigatorStatic STATIC ${SourceFiles})
set_target_properties(FrobnigatorStatic PROPERTIES OUTPUT_NAME Frobnigator)
target_link_libraries(Frobnigator ${Libraries})
Where ContinuumTransfunctioner and Transmogrifier projects include the debug postfix directive SET(CMAKE_DEBUG_POSTFIX "_d") so that libContinuumTransfunctioner_d.so and libTransmogrifier_d.so both exist.
The problem is that the current project appears to be linking against the static library without the _d suffix and complains:
/usr/bin/ld: cannot find -lContinuumTransfunctioner
The Libraries that you pass into the target_link_libraries call are interpreted as filenames, not as target names.
This is the unfortunate fallback for that call in CMake: If you pass a random string to it, that cannot be interpreted in a meaningful way, CMake will always assume it to be plain library name. Sometimes this is just what you want, but the name has to be an exact match for an existing library. The whole debug postfix magic will be lost here.
What you might have wanted to do was to pass a library target name instead. This will trigger a much smarter handling of the dependency and would solve your problem. However, that only works if the library is a known target in the context of the target_link_libraries call. You can easily check this as follows:
if(TARGET ContinuumTransfunctioner)
message("Library target name")
else()
message("Plain library name")
endif()
target_link_libraries(Frobnigator ContinuumTransfunctioner)
So how do you get to the target name case? This depends on how your build is structured. If the library is being built as part of your CMake run, simply make sure that the corresponding add_library call is performed from a subdirectory that is pulled in via add_subdirectory from the file that performs the target_link_libraries call.
If the library in question is an external dependency, you need to build an imported target that carries all the relevant information where to find the library files (including any potential debug postfixes). This can be a bit cumbersome to do manually, so if you can, you might want to use CMake's packaging mechanism to generate this automatically as part of the library's build process.
Here's the solution, courtesy of the good people on the cmake mailing list:
# Note:
# $<$<CONFIG:Debug>:_d> is called a generator expression.
# It outputs _d if the build is debug.
#
set(Libraries
ContinuumTransfunctioner$<$<CONFIG:Debug>:_d>
Transmogrifier$<$<CONFIG:Debug>:_d>
)

Specifying libraries for cmake to link to from command line

I have a huge project managed with CMake and this project has hundreds of components each of them having own source files and each of them linking to a list of libraries, specified with target_link_libraries(${project} some_libraries, some_other_libraries)
Now, what I am aiming for is that:
Without actually modifying any of the CMakeLists.txt I want ALL the projects's target executable to link to some specific libraries.
Is there a way of achieving this? Since this is a one time trial, I don't want to manually hunt down all the CMakeLists.txt files and modify them (yes, this is the other alternative). Just a note, I compile the entire project from command line, using cmake (no cmake gui).
This is kind of a hack, but for a C++ project, you can use CMAKE_CXX_STANDARD_LIBRARIES. For a C project, I think you would use CMAKE_C_STANDARD_LIRBARIES.
Example for C++ that links to libbar and libfoo:
cmake ... -DCMAKE_CXX_STANDARD_LIBRARIES="-lbar -lfoo"
See the documentation here:
https://cmake.org/cmake/help/v3.6/variable/CMAKE_LANG_STANDARD_LIBRARIES.html
This won't be available for older versions of CMake; it was added some time after version 3.0.
This is a dirty, dirty hack, so please only use it for testing.
You can actually overload the add_executable command by defining a function of the same name. Do this close to the top of the top-level CMakeLists.txt:
function (add_executable name)
message("Added executable: " ${name})
_add_executable(${name} ${ARGN})
target_link_libraries(${name$} your_additional_lib)
endfunction()
Note that _add_executable is an internal CMake name that may break in future CMake versions. As of now (version 3.0) it seems to work with all versions though.
You can overload add_library the same way if required.
For more fine-grained control over what is linked, instead of calling target_link_libraries you can also mess with the LINK_LIBRARIES and INTERFACE_LINK_LIBRARIES target properties directly.

CMake External Library Linking?

It seems cmake can't determine which libraries can be used with the current compiler or rather I want cmake to only use libraries that have been compiled with the same compiler.
I am using find_library to find the needed libraries but it seems to be unable to determine if the library is actually usable. It managed to find the library by name but it was using the ".lib" extension when I was making a configuration for MinGW. Do I have to create folders for every compiler I compile libraries for and add if statements for each compiler in my script ? That just seems counter intuitive to what I believed find_library would be capable of. Perhaps I am misusing it ? Anyone have any better ideas ?
It seems you're a bit confused: you're right when you suggest that you need different libraries for MinGW and Visual Studio on Windows. But you're wrong when saying that .lib files can't be used by MinGW. Both Visual Studio and MinGW use .lib files to link to libraries on Windows.
The find_library command purpose is only to find libraries. Nothing more, so it's doing its job here.
If you want to make sure that the libraries found can be used by your compiler, you'll have to check that those libraries can be used by your compiler using try_compile:
find_library(YOURLIB_LIBRARY yourlib)
if (YOURLIB_LIBRARY)
try_compile(YOURLIB_WORKS
bindir
somefile.c
LINK_LIBRARIES ${YOURLIB_LIBRARY})
if (YOURLIB_WORKS)
# do something with your library
else()
# warn the user of stop the configuration process
endif()
endif()