mirror of
1
0
Fork 0

Adding some specifics

This commit is contained in:
Henry Fredrick Schreiner 2018-03-01 22:01:04 +01:00
parent bd8da983c5
commit 2f80aa633f
4 changed files with 189 additions and 3 deletions

View File

@ -20,8 +20,8 @@
* [Debugging (X)](chapters/debug.md)
## Specific packages
* [CUDA (X)](specifics/CUDA.md)
* [OpenMP (X)](specifics/OpenMP.md)
* [CUDA](specifics/CUDA.md)
* [OpenMP](specifics/OpenMP.md)
* [Boost (X)](specifics/Boost.md)
* [MPI (X)](specifics/MPI.md)
* [MPI](specifics/MPI.md)
* [ROOT (X)](specifics/ROOT.md)

82
specifics/CUDA.md Normal file
View File

@ -0,0 +1,82 @@
# CUDA (in progress)
CUDA support is available in two flavors. The new method, introduced in CMake 3.8 (3.9 for Windows), will be what I focus on first. The old method will be covered afterwards, but as you'll see, it's uglier and harder to get right. I'd stick to requiring CMake 3.8 or 3.9 for CUDA.
A good resource for CUDA and Modern CMake is [this talk](http://on-demand.gputechconf.com/gtc/2017/presentation/S7438-robert-maynard-build-systems-combining-cuda-and-machine-learning.pdf) by CMake developer Robert Maynard at GTC 2017.
## Method 1: CUDA as a First Class Language
This method is quite new, and doesn't seem to have much documentation. There are several issues you need to watch out for when using it, but overall is should be a much nicer and cleaner way to use CUDA.
### Adding the CUDA Language
There are two ways to enable CUDA support. If CUDA is not optional:
```cmake
project(MY_PROJECT LANGUAGES CUDA CXX)
```
You'll probably want `CXX` listed here also. And, if CUDA is optional, you'll want to put this in somewhere conditionally:
```cmake
enable_language(CUDA)
```
### Variables for CUDA
Many variables with `CXX` in the name have a CUDA version with `CUDA` instead. For example, to set the C++ standard required for CUDA,
```
if(NOT DEFINED CMAKE_CUDA_STANDARD)
set(CMAKE_CUDA_STANDARD 11)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()
```
### Adding a library
This is the easy part; as long as you use `.cu` for CUDA files, you can just add libraries like you normally would.
You can also use separable compilation:
```cmake
set_target_properties(mylib PROPERTIES
CUDA_SEPERABLE_COMPILATION ON)
```
You can also direcly make a PTX file with the `CUDA_PTX_COMPILATION` property.
### Working with targets
Using targets should work similarly to CXX, but there's a problem. If you include a target that includes compiler options (flags), most of the time, the options will not be protected by the correct includes (and the chances of them having the correct CUDA wrapper is even smaller). Here's what a correct compiler options line should look like:
```cmake
```
However, if you using almost any find_package, and using the Modern CMake methods of targets and inheritence, everything will break. I've learned that the hard way.
For now, here's a pretty reasonable solution, _as long as you know the un-aliased target name_. It's a function that will fix a C++ only target by wrapping the flags if using a CUDA compiler:
```cmake
function(CUDA_CONVERT_FLAGS EXISTING_TARGET)
get_property(old_flags TARGET ${EXISTING_TARGET} PROPERTY INTERFACE_COMPILE_OPTIONS)
if(NOT "${old_flags}" STREQUAL "")
string(REPLACE ";" "," CUDA_flags "${old_flags}")
set_property(TARGET ${EXISTING_TARGET} PROPERTY INTERFACE_COMPILE_OPTIONS
"$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CXX>>:${old_flags}>$<$<BUILD_INTERFACE:$<COMPILE_LANGUAGE:CUDA>>:-Xcompiler=${CUDA_flags}>"
)
endif()
endfunction()
```
> ### Note that FindCUDA is deprecated, but for now, the following functions require FindCUDA:
>
> * CUDA version checks / picking a version
> * Architecture detection
> * Linking to CUDA libraries from non-.cu files
## Method 2: FindCUDA

55
specifics/MPI.md Normal file
View File

@ -0,0 +1,55 @@
# MPI
To add MPI, like OpenMP, you'll be best off with CMake 3.9+.
```cmake
find_package(MPI REQUIRED)
message(STATUS "Run: ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} EXECUTABLE ${MPIEXEC_POSTFLAGS} ARGS")
target_link_libraries(MyTarget PUBLIC MPI::MPI_CXX)
```
However, you can imitate this on CMake 3.1+ with:
```cmake
find_package(MPI REQUIRED)
# For supporting CMake < 3.9:
if(NOT TARGET MPI::MPI_CXX)
add_library(MPI_LIB_TARGET INTERFACE)
add_library(MPI::MPI_CXX ALIAS MPI_LIB_TARGET)
target_compile_options(MPI_LIB_TARGET INTERFACE "${MPI_CXX_COMPILE_FLAGS}")
target_include_directories(MPI_LIB_TARGET INTERFACE "${MPI_CXX_INCLUDE_PATH}")
target_link_libraries(MPI_LIB_TARGET INTERFACE ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES})
endif()
message(STATUS "Run: ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} EXECUTABLE ${MPIEXEC_POSTFLAGS} ARGS")
target_link_libraries(MyTarget PUBLIC MPI::MPI_CXX)
```
Or,
```cmake
find_package(MPI REQUIRED)
# For supporting CMake < 3.9:
if(NOT TARGET MPI::MPI_CXX)
add_library(MPI::MPI_CXX IMPORTED INTERFACE)
set_property(TARGET MPI::MPI_CXX
PROPERTY INTERFACE_COMPILE_OPTIONS ${MPI_CXX_COMPILE_FLAGS})
set_property(TARGET MPI::MPI_CXX
PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MPI_CXX_INCLUDE_PATH}")
set_property(TARGET MPI::MPI_CXX
PROPERTY INTERFACE_LINK_LIBRARIES ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES})
endif()
message(STATUS "Run: ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MPIEXEC_MAX_NUMPROCS} ${MPIEXEC_PREFLAGS} EXECUTABLE ${MPIEXEC_POSTFLAGS} ARGS")
target_link_libraries(MyTarget PUBLIC MPI::MPI_CXX)
```

49
specifics/OpenMP.md Normal file
View File

@ -0,0 +1,49 @@
# OpenMP
[OpenMP] support was drastically improved in CMake 3.9+. The Modern(TM) way to add OpenMP to a target is:
```cmake
find_package(OpenMP)
if(OpenMP_CXX_FOUND)
target_link_libraries(MyTarget PUBLIC OpenMP::OpenMP_CXX)
endif()
```
This not only is cleaner than the old method, it will also correctly set the library link line differently from the compile line if needed. However, if you need to support older CMake, the following works on CMake 3.1+:
```cmake
# For CMake < 3.9, we need to make the target ourselves
if(NOT TARGET OpenMP::OpenMP_CXX)
add_library(OpenMP_TARGET INTERFACE)
add_library(OpenMP::OpenMP_CXX ALIAS OpenMP_TARGET)
target_compile_options(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS})
# Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang)
target_link_libraries(OpenMP_TARGET INTERFACE ${OpenMP_CXX_FLAGS})
find_package(Threads REQUIRED)
target_link_libraries(OpenMP_TARGET INTERFACE Threads::Threads)
endif()
target_link_libraries(MyTarget PUBLIC OpenMP::OpenMP_CXX)
```
or,
```cmake
# For CMake < 3.9, we need to make the target ourselves
if(NOT TARGET OpenMP::OpenMP_CXX)
add_library(OpenMP::OpenMP_CXX IMPORTED INTERFACE)
set_property(TARGET OpenMP::OpenMP_CXX
PROPERTY INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS})
# Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang)
set_property(TARGET OpenMP::OpenMP_CXX
PROPERTY INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS})
find_package(Threads REQUIRED)
target_link_libraries(MyTarget INTERFACE Threads::Threads)
endif()
target_link_libraries(MyTarget PUBLIC OpenMP::OpenMP_CXX)
```
[OpenMP]: https://cmake.org/cmake/help/latest/module/FindOpenMP.html