From 48b452cefc06ed6e49f5baef8607e7ef77057070 Mon Sep 17 00:00:00 2001 From: theComputeKid Date: Sat, 3 Jun 2023 14:26:01 +0100 Subject: [PATCH] Add initial Linux support. --- GNUmakefile | 23 +++++++++ README.md | 64 +++++++++++++++++------- premake5-cuda.lua | 2 + src/premake5-cuda-nvcc.lua | 100 +++++++++++++++++++++++++++++++++++++ test/premake5.lua | 26 ++++++++-- 5 files changed, 193 insertions(+), 22 deletions(-) create mode 100644 GNUmakefile create mode 100644 src/premake5-cuda-nvcc.lua diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..ef8aa21 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,23 @@ +#* Makefile to build premake-core for tests on windows +PREMAKE_OUT := vendor/premake-core/bin/release/premake5 + +#* Runs the tests. +all: build + @echo Testing debug config + @cd test/out/bin/debug && ./ExampleProjectExe && ./ExampleProjectExeNonCUDA + @echo Testing release config + @cd test/out/bin/release && ./ExampleProjectExe && ./ExampleProjectExeNonCUDA + +build: premake + @cd test/out && $(MAKE) config=debug + @cd test/out && $(MAKE) config=release + +premake: $(PREMAKE_OUT) + @$(PREMAKE_OUT) --file=test/premake5.lua gmake2 + +$(PREMAKE_OUT): + @cd vendor/premake-core && $(MAKE) -f Bootstrap.mak linux PLATFORM=x64 + +clean: + @rm -f $(PREMAKE_OUT) + @rm -rf test/out diff --git a/README.md b/README.md index c6ea0b3..d83ba39 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,61 @@

a premake5 extension for cuda

-

premake5CUDA

+

premake5-CUDA

-Compiles CUDA code using the Visual Studio CUDA Toolkit extension. Enabled macros (listed in `src/cuda-exported-variables.lua`): -- `cudaFiles` (Table) -> list of files to be compiled by NVCC to binary (relative path from solution root) -- `cudaPTXFiles` (Table) -> list of files to be compiled by NVCC to PTX (relative path from solution root) -- `cudaRelocatableCode` (Bool) -> triggers -rdc=true -- `cudaExtensibleWholeProgram` (Bool) -> triggers extensible whole program compilation -- `cudaCompilerOptions` (Table) -> passed to nvcc -- `cudaLinkerOptions` (Table) -> passed to nvlink -- `cudaFastMath` (Bool) -> triggers fast math optimizations -- `cudaVerbosePTXAS` (Bool) -> triggers code gen verbosity -- `cudaMaxRegCount` (String) -> number to determine the max used registers -- `cudaKeep` (Bool) -> keeps preprocessed output -- `cudaPath` (String) -> custom CUDA install path to override the VS integration plugin -- `cudaGenLineInfo` (Bool) -> generates line info - -Files specified by the premake5 options `files` are compiled by the MSVC and not nvcc. +Compiles CUDA code using the Visual Studio CUDA Toolkit extension on Windows and `nvcc` on Linux. Enabled macros (listed in `src/cuda-exported-variables.lua`): +- `cudaFiles` (Table) -> list of files to be compiled by NVCC to binary (relative path from solution root). +- `cudaPTXFiles` (Table) -> list of files to be compiled by NVCC to PTX (relative path from solution root) - Windows only. +- `cudaRelocatableCode` (Bool) -> triggers -rdc=true. +- `cudaExtensibleWholeProgram` (Bool) -> triggers extensible whole program compilation. +- `cudaCompilerOptions` (Table) -> passed to nvcc. +- `cudaLinkerOptions` (Table) -> passed to nvlink. +- `cudaFastMath` (Bool) -> triggers fast math optimizations. +- `cudaVerbosePTXAS` (Bool) -> triggers code gen verbosity. +- `cudaMaxRegCount` (String) -> number to determine the max used registers. +- `cudaKeep` (Bool) -> keeps preprocessed output. +- `cudaPath` (String) -> custom CUDA install path. +- `cudaGenLineInfo` (Bool) -> generates line info. + +---------------- +Notes for Windows: +---------------- + +Files specified by `files` are compiled by `cl` and not `nvcc`. An example is provided in the test folder where a CUDA executable project containing C++, PTX and CUDA files is linked against a CUDA shared library project. If you clone this repo recursively (i.e. with `-recursive`), it will also pull the premake5 repo, which can be used via the makefile to build premake and then the tests (e.g. via the `nmake` command). You do not need the premake5 repo unless you want to build the tests. To use: - Install the CUDA toolkit, along with its Visual Studio integration. -- Copy the premake5-cuda folder to your project +- Copy the premake5-cuda folder to your project. - Include it in your premake5.lua file as shown in the example. Tested with Visual Studio 2022 (toolkit v143) with CUDA toolkit 12.1 VS integration. Note: If PTX is requested, it will be found in the output object folder, with the .obj extension, though, it can be opened with a text editor for inspection. + +---------------- +Notes for Linux: +---------------- + +This extension was primarily made for VS on Windows, with the CUDA toolkit extension. Linux is a work in progress and does not have feature parity with Windows yet. Differences are: +- toolset must be set as `"nvcc"`. +- rules must be set to `'cu'`. +- `cudaPTXFiles` not supported. +- the list of cuda files must be provided in `files` instead of `cudaFiles`. +- unlike Windows, the whole project is compiled by `nvcc` and not just the `.cu` files. + +See test premake5 file for how linux config differs. The differences are summarised here: + +``` + if os.target() == "windows" then + cudaFiles { "exe/cu/**.cu" } -- files to be compiled into binaries by VS CUDA. + cudaPTXFiles { "exe/ptx/**.cu" } -- files to be compiled into ptx, Windows only. + else + toolset "nvcc" + files { "exe/cu/**.cu" } + rules {"cu"} + end +``` + +Admittedly, Linux support is a bit clunky but it should get the job done. diff --git a/premake5-cuda.lua b/premake5-cuda.lua index bb3e763..2757070 100644 --- a/premake5-cuda.lua +++ b/premake5-cuda.lua @@ -2,4 +2,6 @@ require("src/cuda-exported-variables") if os.target() == "windows" then dofile("src/premake5-cuda-vs.lua") +elseif os.target() == "linux" then + dofile("src/premake5-cuda-nvcc.lua") end diff --git a/src/premake5-cuda-nvcc.lua b/src/premake5-cuda-nvcc.lua new file mode 100644 index 0000000..1d59c47 --- /dev/null +++ b/src/premake5-cuda-nvcc.lua @@ -0,0 +1,100 @@ +--* Creates an NVCC toolset for Linux. + +rule 'cu' + fileExtension { ".cu" } + buildoutputs { "$(OBJDIR)/%{file.objname}.cu.o" } + buildmessage '$(notdir $<)' + buildcommands {'$(CXX) %{premake.modules.gmake2.cpp.fileFlags(cfg, file)} $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<"'} + +premake.tools.nvcc = {} + +local nvcc = premake.tools.nvcc +local gcc = premake.tools.gcc + +nvcc.getcflags = gcc.getcflags +nvcc.getcppflags = gcc.getcppflags +nvcc.getforceincludes = gcc.getforceincludes +nvcc.getdefines = gcc.getdefines +nvcc.getundefines = gcc.getundefines +nvcc.getrunpathdirs = gcc.getrunpathdirs +nvcc.getincludedirs = gcc.getincludedirs +nvcc.getLibraryDirectories = gcc.getLibraryDirectories +nvcc.getlinks = gcc.getlinks +nvcc.getmakesettings = gcc.getmakesettings + +nvcc.cxxflags = { + cudaRelocatableCode = { + On = "-rdc=true", + Off = "-rdc=false" + }, + cudaExtensibleWholeProgram = { + On = "-ewp" + }, + cudaFastMath = { + On = "-use_fast_math" + }, + cudaVerbosePTXAS = { + On = "--ptxas-options=--verbose" + }, + cudaKeep = { + On = "-keep" + }, + cudaGenLineInfo = { + On = "-lineinfo" + }, + kind = { + SharedLib = "-fpic" + } +} + +function nvcc.gettoolname (cfg, tool) + + local prefix = "" + if cfg.project.cudaPath == nil then + prefix = "/usr/local/cuda/bin/" + else + prefix = cfg.project.cudaPath .. "/bin/" + end + + if tool == "cc" then + name = prefix .. "nvcc" + elseif tool == "cxx" then + name = prefix .. "nvcc" + elseif tool == "ar" then + name = "ar" + else + name = nil + end + return name +end + +function nvcc.getcxxflags(cfg) + local flags = premake.config.mapFlags(cfg, nvcc.cxxflags) + local gccFlags = premake.config.mapFlags(cfg, gcc.cxxflags) + flags = table.join(flags,gccFlags) + flags = table.join({"-forward-unknown-to-host-compiler"}, flags) + + if cfg.cudaCompilerOptions ~= nil then + local cudaFlags = cfg.cudaCompilerOptions + flags = table.join(flags, cudaFlags) + end + + if cfg.cudaMaxRegCount ~= nil then + flags = table.join(flags, { "--maxrregcount " .. cfg.cudaMaxRegCount}) + end + + return flags +end + +function nvcc.getldflags(cfg) + local flags = premake.config.mapFlags(cfg, gcc.ldflags) + flags = table.join({"-forward-unknown-to-host-compiler"}, flags) + flags = table.join({"-Xlinker=-rpath,'$$ORIGIN'"}, flags) + + if cfg.cudaLinkerOptions ~= nil then + local cudaFlags = cfg.cudaLinkerOptions + flags = table.join(flags, cudaFlags) + end + + return flags +end diff --git a/test/premake5.lua b/test/premake5.lua index a4dcb5a..3cc3c38 100644 --- a/test/premake5.lua +++ b/test/premake5.lua @@ -51,8 +51,17 @@ project "ExampleProjectExe" buildcustomizations "BuildCustomizations/CUDA 12.1" externalwarnings "Off" -- thrust gives a lot of warnings - cudaFiles { "exe/cu/**.cu" } -- files to be compiled into binaries - cudaPTXFiles { "exe/ptx/**.cu" } -- files to be compiled into ptx + + if os.target() == "windows" then + cudaFiles { "exe/cu/**.cu" } -- files to be compiled into binaries by VS CUDA. + cudaPTXFiles { "exe/ptx/**.cu" } -- files to be compiled into ptx, Windows only. + else + toolset "nvcc" + cudaPath "/usr/local/cuda" + files { "exe/cu/**.cu" } + rules {"cu"} + end + cudaKeep "On" -- keep temporary output files cudaFastMath "On" cudaRelocatableCode "On" @@ -74,10 +83,17 @@ project "ExampleProjectDLL" buildcustomizations "BuildCustomizations/CUDA 12.1" - -- Just in case we want the VS CUDA extension to use a custom version of CUDA - cudaPath "$(CUDA_PATH)" + if os.target() == "windows" then + -- Just in case we want the VS CUDA extension to use a custom version of CUDA + cudaPath "$(CUDA_PATH)" + cudaFiles { "lib/**.cu" } + else + toolset "nvcc" + cudaPath "/usr/local/cuda" + files { "lib/**.cu" } + rules {"cu"} + end - cudaFiles { "lib/**.cu" } cudaRelocatableCode "On" defines { "PREMAKE_CUDA_EXPORT_API" }