CMake to generate a MSVC CUDA project that targets newer devices - visual-studio

My PC has a GTX 580 (compute capability 2.0).
I want to compile a CUDA source that uses dynamic parallelism, a feature introduced in compute capability 3.5.
I know I will not be able to run the program on my GPU, however, it should be possible to compile this code on my machine. I'm assuming this because I can compile with no problems the CUDA samples that use 3.5 capability. These samples come with Visual Studio projects that were "manually generated" (I guess).
I believe my problem is with CMake. I'm using CMake to generate a Visual Studio 2012 project.
My first CMakeLists.txt looked like this:
PROJECT(sample-cuda-tests)
FIND_PACKAGE(CUDA REQUIRED)
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
FILE(GLOB_RECURSE includes ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h )
FILE(GLOB_RECURSE sources ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu )
CUDA_ADD_EXECUTABLE(sample-cuda-tests ${includes} ${sources})
TARGET_LINK_LIBRARIES(sample-cuda-tests ${CUDA_LIBRARIES})
Then, when compiling with the generated Visual Studio 2012 project, I got a warning followed by an error:
warning : The 'compute_10' and 'sm_10' architectures are deprecated, and may be removed in a future release.
error : calling a __global__ function from a __global__ function is only allowed on the compute_35 architecture or above
What was expected. Then I added
list(APPEND CUDA_NVCC_FLAGS -gencode arch=compute_35,code=sm_35)
to the CMakeLists. The warning disappeared, but I got:
error : kernel launch from __device__ or __global__ functions requires separate compilation mode
Ok. So I added to the CMakeLists:
set(CUDA_SEPARABLE_COMPILATION ON)
...and received this:
fatal error : nvcc supports '--relocatable-device-code=true (-rdc=true)', '--device-c (-dc)', and '--device-link (-dlink)' only when targeting sm_20 or higher
What is weird because I thought I was targeting sm_35 (higher than sm_20).
Later I discovered I can set some options directly in CUDA_ADD_EXECUTABLE command. So I removed the line that was appending values to CUDA_NVCC_FLAGS and changed CUDA_ADD_EXECUTABLE command to:
CUDA_ADD_EXECUTABLE(sample-cuda-tests ${includes} ${sources} OPTIONS -gencode arch=compute_35,code=sm_35)
What I got was:
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v6.0\bin\crt\link.stub : fatal error C1083: Cannot open compiler generated file: 'C:/Users/sms/Desktop/sample-cuda-tests/CMakeFiles/sample-cuda-tests.dir/Debug/sample-cuda-tests_intermediate_link.obj': No such file or directory
No idea where to go now. Appreciate any help.
I'm using CUDA SDK 6.0 on Windows 7.

As of CMake 3.1.0, CMake script misses creating a directory to put the intermediate file in.
Add the following snippet in the FindCUDA.cmake
get_filename_component(output_file_path "${output_file}" PATH)
add_custom_command(
TARGET ${cuda_target}
PRE_LINK
COMMAND ${CMAKE_COMMAND} -E make_directory ${output_file_path}
)
right before
if (do_obj_build_rule)
in function CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS

Turned out to be a bug on FindCUDA.cmake.
When setting CUDA_SEPARABLE_COMPILATION to ON, if .cu files are not in the same folder of CMakeLists.txt, intermediate linkage objects are generated in the wrong folder, causing a compilation error that, on Visual Studio, looks like this:
Cannot open compiler generated file: 'project_path/CMakeFiles/project_name/Debug/project_name_intermediate_link.obj': No such file or directory.
I've opened an issue in CMake bug tracker:
http://public.kitware.com/Bug/view.php?id=15016
(the bug is better described there)

Related

Duplicated code generation flags on CMAKE Cuda/ptx project

I want to compile cuda to ptx for embedding. For this I am using CMAKE 3.18.5 with visual studio 16(2019) generator, which is a requirement from the project. The problem I am having is that the target flags are duplicated compute_75,compute_75;compute_75,sm_75 and because of that nvcc refuses to compile it to ptx.
2>C:\Program Files (x86)\Microsoft Visual
Studio\2019\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations\CUDA
11.2.targets(625,9): error : More than 1 Code Generation option is specified, this is only allowed if NVCC Compilation Type is 'compile'
or 'fatbin'.
For a minimal working example I use a code example for how to do this from a github repo which was
featured in nvidia devblog. This example works.
I change the example to require CMAKE 3.18 (from 3.8) and add
set_property(TARGET CudaPTX PROPERTY CUDA_ARCHITECTURES 75)
set_property(TARGET ExportPTX PROPERTY CUDA_ARCHITECTURES off)
At line 51 (after target_include_directories) and my problem is manifested.
screenshot.
What am I doing wrong?
How do I begin debugging something like this?
How can I change my code example to compile, given I require cmake 3.18 and vs2019?
This is due to CMake generating architectures for both real and virtual devices, which is unfortunately incompatible with PTX generation.
Using the following forces using only the virtual architecture, and fixes the problem:
set(CMAKE_CUDA_ARCHITECTURES 75-virtual)

Building ARM64 ASM in Visual Studio with CMake

I'm working on a cross-platform project which has some hand-written assembly to optimize performance for various CPU architectures. I'm converting this project to CMake from a proprietary build system, starting with compiling using Visual Studio on Windows. For x86 and AMD64, I've been able to assemble and link everything just fine, but I can't get it to work on ARM64 (or presumably ARM32, though I haven't tried that yet).
I'm including the ASM files in my sources as follows:
if(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64")
list(APPEND SOURCES
amd64/aesasm.asm
...)
set_source_files_properties(
amd64/aesasm.asm
...
PROPERTY LANGUAGE ASM_MASM)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "X86")
# ...
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64")
list(APPEND SOURCES
arm64/fdef_asm.asm
...)
set_source_files_properties(
arm64/fdef_asm.asm
...
PROPERTY LANGUAGE ASM_MASM)
Then in my top-level CMakeLists.txt, I enable MASM using enable_language(ASM_MASM). For x86 and AMD64, CMake automatically finds ml/ml64.exe, configures the Visual Studio project correctly, and everything works.
But for ARM64, if I try the same thing, I get this error from Visual Studio when trying to build: MSB3721: The command "echo MASM not supported on this platform. As far as I can tell, this is because Visual Studio considers ARM assembly to be a different dialect, "MARMASM", with a different executable name for the assembler (armasm/armasm64.exe).
I tried setting enable_language(ASM_MARMASM) in my ARM64 toolchain file, but CMake does not recognize this as an ASM dialect, and gives me this error:
CMake Error: Could not find cmake module file: CMakeDetermineASM_MARMASMCompiler.cmake
CMake Error: Could not find cmake module file: F:/os/src/symcrypt/bin/CMakeFiles/3.15.3/CMakeASM_MARMASMCompiler.cmake
CMake Error at CMakeLists.txt:49 (enable_language):
No CMAKE_ASM_MARMASM_COMPILER could be found.
I also tried manually setting the assembler:
get_filename_component(VS_TOOLS_DIRECTORY ${CMAKE_LINKER} DIRECTORY)
find_file(ARM64_COMPILER "armasm64.exe" HINTS ${VS_TOOLS_DIRECTORY})
set(CMAKE_ASM_MARMASM_COMPILER ${ARM64_COMPILER})
enable_language(ASM_MARMASM)
message(STATUS "Manually set assembler to ${CMAKE_ASM_MARMASM_COMPILER}")
But this does not work either; I still get an error that No CMAKE_ASM_MARMASM_COMPILER could be found.
How can I include ARM/ARM64 assembly in my project?
Looks like CMake (still) does not have support for this. I found some bits in the .NET source code to work around it:
https://github.com/dotnet/runtime/blob/f8f63b1fde85119c925313caa475d9936297b463/eng/native/functions.cmake#L173-L207
and
https://github.com/dotnet/runtime/blob/f8f63b1fde85119c925313caa475d9936297b463/eng/native/configurecompiler.cmake#L611-L626
edit: As reference, here's the commit for a project I had this requirement for: https://dyncall.org/pub/dyncall/dyncall/rev/451299d50c1a

Boost VS2017 linking to the wrong DLL

I have a CMake file which does this:
find_package(Boost COMPONENTS system filesystem)
add_library(MyModule MODULE main.cpp)
target_include_directories(MyModule PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(MyModule Boost::system Boost::filesystem)
I'm using VS 2017 as my generator. When I generate the project file with cmake, it finds boost_system-vc141-mt-1_63.lib and I can see that it is in the linking rules of the vcxproj. However, when I try to compile I get this error:
LINK : fatal error LNK1104: cannot open file 'libboost_system-vc140-mt-1_63.lib
Note the different generators (vc140 vs vc141). I know my compiler has output the right values because I built boost from source, so I tried to just rename vc141 to vc140, but the error stayed the same. I also confirmed that vc140 is not referenced in the project file.
What's going on? How can I force boost to link to the correct version?
When building with Visual Studio, boost has some pragma statements which do the linking for you. This is called "Auto-linking" and it over-rides any command-line arguments you may be passing to the linker.
The solution is to define BOOST_ALL_NO_LIB. This can be done in two ways:
In source code before including boost headers as #define BOOST_ALL_NO_LIB.
It could be added to your cmake file as: add_definitions("-DBOOST_ALL_NO_LIB").
As of CMake 3.5: Use the disable_autolinking imported target:
target_link_libraries(MyModule Boost::system Boost::filesystem Boost::disable_autolinking)

Cross compiling for arm using crystax NDK

The android ndk supplied by google is unable to compile call to c++11 functions such as std::to_string() and std::stoul etc. {I had tried it in r10b one from the official site}. So the suggestion in SO was to try crystax NDK. I have downloaded and placed the root folder next to the google's NDK. All I changed in my root CMakeLists.txt file was:
from:
set(PLATFORM_PREFIX "/some-path/android-ndk-r10b/platforms/android-19/arch-arm")
set(PLATFORM_FLAGS "-fPIC -Wno-psabi --sysroot=${PLATFORM_PREFIX}")
set(CMAKE_CXX_FLAGS "${PLATFORM_FLAGS} -march=armv7-a -mfloat-abi=softfp -mfpu=neon" CACHE STRING "")
To:
set(PLATFORM_PREFIX "/some-path/android-ndk-r8-crystax-1/platforms/android-14/arch-arm")
set(PLATFORM_FLAGS "-fPIC -Wno-psabi --sysroot=${PLATFORM_PREFIX}")
set(CMAKE_CXX_FLAGS "${PLATFORM_FLAGS} -march=armv7-a -mfloat-abi=softfp -mfpu=neon" CACHE STRING "")
and cmake command-line from:
cmake .. -DCMAKE_CXX_COMPILER=/some-path/android-ndk-r10b/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ -DCMAKE_C_COMPILER=/some-path/android-ndk-r10b/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc -DANDROID_BUILD=ON -DANDROID_NDK_ROOT=/some-path/android-ndk-r10b
To:
cmake .. -DCMAKE_CXX_COMPILER=/some-path/android-ndk-r8-crystax-1/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/arm-linux-androideabi-g++ -DCMAKE_C_COMPILER=/some-path/android-ndk-r8-crystax-1/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc -DANDROID_BUILD=ON -DANDROID_NDK_ROOT=/some-path/android-ndk-r8-crystax-1
ie., changed from normal ndk to crystax-ndk. The program was compiling fine previously till it tried to compile a file with call to std::to_string() etc. But after the change Cmake gives an error that it is unable to compile a simple test program because:
/some-path/android-ndk-r8-crystax-1/toolchains/arm-linux-androideabi-4.7/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.7/../../../../arm-linux-androideabi/bin/ld:
error: cannot find -lcrystax
I can see libcrystax.a and .so in directorie:
/some-path/android-ndk-r8-crystax-1/sources/crystax/libs/armeabi-v7a
I tried adding link_directories("path-to-above") right at the beginning of the CMakeLists.txt file too, but that didn't solve it either.
It should find it there (after i supply the --sysroot etc above) just like the normal ndk. So how should this be solved ? Any other cmake variable to be set or something ?
I don't know how your cmake-based build system works, but actually if you properly add path /some-path/android-ndk-r8-crystax-1/sources/crystax/libs/armeabi-v7a to linker search paths, it should find libcrystax and link with it successfully.
Please note that NDK have several parts separated each from other - i.e. sysroot, libcrystax, C++ library - all are separated. It is done to work with NDK build system which offer some flexibility choosing C++ standard library implementation, and NDK build system know where to find all of them. In your case this approach is not so good so I suggest you first make standalone toolchain, which contains all things assembled together. In other words, it would be classic cross-compile toolchain which contains sysroot, libcrystax and GNU C++ standard library in places known to compiler/linker without passing of any additional options.
To create such toolchain, cd to NDK root directory and run the following command:
./build/tools/make-standalone-toolchain.sh --system=linux-x86_64 --toolchain=arm-linux-androideabi-4.7 --platform=android-14 --install-dir=$HOME/arm-linux-androideabi
Then use $HOME/arm-linux-androideabi as full standalone toolchain for your cmake-based build system.
Please note, however, that application built with CrystaX NDK r8 will not run on newest Android 5.0 due to changes in Bionic (libc). Previous Android versions (<=4.4) are all fine. We fixed that issue (and many others) in upcoming r10 release which is on final testing stage. In the meantime you could adopt your project to our r8 release and quickly switch to r10 when it done - the same approach will work with r10 as well as with r8.

Building Clang on Windows

I'm trying to build LLVM/Clang on Windows 7 with Microsoft C++ 2013. Building LLVM spat out a few error messages along the way but mostly seemed to be succeeding and did end up creating a folder full of exe's so that part seems to have worked. When I try to build Clang:
C:\clang>\CMake\bin\cmake.exe ..\clang-3.4 -DCLANG_PATH_TO_LLVM_BUILD=/llvm
CMake Error at CMakeLists.txt:29 (message):
Please set CLANG_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.
And I get the same error message whether I omit CLANG_PATH_TO_LLVM_BUILD, define it in CMakeLists.txt or an environment variable instead of the command line, set it to possibly relevant subdirectories of /llvm etc.
What am I missing?
You're not following the instructions on this page correctly, under "Using Visual Studio". You will end up with
/
/llvm
/llvm/CMakeLists.txt
/llvm/tools/clang
/llvm/tools/clang/CMakeLists.txt
Step 4, repeated here for clarity:
Run CMake to generate the Visual Studio solution and project files:
cd ..\.. (back to where you started)
mkdir build (for building without polluting the source dir)
cd build
If you are using Visual Studio 2012: cmake -G "Visual Studio 11" ..\llvm
That last bit needs to be run from inside the VS Command Prompt, but you seem to have that sorted out. You can also generate "NMake makefiles" if you don't use the IDE to build. Anyways, the point is that you should call cmake on the toplevel CMakeLists.txt file, not on the clang one directly. Clang will be built as part of the build process. You can even add libc++ and compiler-rt to the llvm/projects directory to have these built automatically on platforms that support them.
What you are doing is building clang "out of tree". Which is possible and even supported, but only really useful in certain circumstances. You'll need a previously built build of LLVM in some directory. You then set CLANG_PATH_TO_LLVM_BUILD to the directory containing the built LLVM files (this is not the source directory). But as I said, that's making things needlessly difficult.

Resources