diff --git a/.gitignore b/.gitignore index f281046..cbdec96 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,5 @@ *.ilk [Bb]in/* !smp_* -*Caches/ \ No newline at end of file +*Caches/ +!bin2c.exe diff --git a/bin2c.exe b/bin2c.exe new file mode 100644 index 0000000..093eb1d Binary files /dev/null and b/bin2c.exe differ diff --git a/include/projectGenerator.h b/include/projectGenerator.h index e394163..d831df2 100644 --- a/include/projectGenerator.h +++ b/include/projectGenerator.h @@ -445,6 +445,22 @@ class ProjectGenerator */ void outputCUDATools(string& projectTemplate) const; + /** + * Output CUDA source files with custom build steps. + * @param [in,out] fileList The list of CUDA files to process. + * @param [in,out] projectTemplate The project template. + * @param [in,out] filterTemplate The filter template. + * @param [in,out] foundObjects The list of found object files. + * @param [in,out] foundFilters The set of found filters. + * @param staticOnly True to only include in static builds. + * @param sharedOnly True to only include in shared builds. + * @param bit32Only True to only include in 32-bit builds. + * @param bit64Only True to only include in 64-bit builds. + */ + void outputCUDASourceFiles(StaticList& fileList, string& projectTemplate, string& filterTemplate, + StaticList& foundObjects, set& foundFilters, bool staticOnly = false, bool sharedOnly = false, + bool bit32Only = false, bool bit64Only = false) const; + bool outputDependencyLibs(string& projectTemplate, bool winrt, bool program); /** diff --git a/project_generate.vcxproj b/project_generate.vcxproj index f500553..0b0d2f0 100644 --- a/project_generate.vcxproj +++ b/project_generate.vcxproj @@ -38,6 +38,9 @@ + + + {FA1D2C31-D809-4021-9DE4-7552704175EE} ffmpeg_generate diff --git a/project_generate.vcxproj.filters b/project_generate.vcxproj.filters index b6203bd..4f648f9 100644 --- a/project_generate.vcxproj.filters +++ b/project_generate.vcxproj.filters @@ -62,4 +62,7 @@ Resource Files + + + \ No newline at end of file diff --git a/source/Templates.rc b/source/Templates.rc index e32aca5..36fa606 100644 Binary files a/source/Templates.rc and b/source/Templates.rc differ diff --git a/source/projectGenerator.cpp b/source/projectGenerator.cpp index dfd4cbb..07468ec 100644 --- a/source/projectGenerator.cpp +++ b/source/projectGenerator.cpp @@ -35,6 +35,7 @@ #define TEMPLATE_PROPS_WINRT_ID 109 #define TEMPLATE_FILE_PROPS_ID 110 #define TEMPLATE_SLN_NOWINRT_ID 111 +#define BIN2C_EXE_ID 112 bool ProjectGenerator::passAllMake() { @@ -1049,16 +1050,15 @@ void ProjectGenerator::outputSourceFiles(string& projectTemplate, string& filter // Output CUDA files if (!m_includesCU.empty()) { if (m_configHelper.isCUDAEnabled()) { - // outputSourceFileType( - // m_includesCU, "CudaCompile", "Source", projectTemplate, filterTemplate, foundObjects, foundFilters, - // true); - /*for (auto& i : m_includesConditionalCU) { + outputCUDASourceFiles(m_includesCU, projectTemplate, filterTemplate, foundObjects, foundFilters); + + // Process conditional CUDA files + for (auto& i : m_includesConditionalCU) { fileList.clear(); fileList.emplace_back(i.first); - outputSourceFileType(fileList, "CudaCompile", "Source", projectTemplate, filterTemplate, foundObjects, - foundFilters, true, i.second.isStatic, i.second.isShared, i.second.is32, i.second.is64); - }*/ - outputError("CUDA files detected in project. CUDA compilation is not currently supported"); + outputCUDASourceFiles(fileList, projectTemplate, filterTemplate, foundObjects, foundFilters, + i.second.isStatic, i.second.isShared, i.second.is32, i.second.is64); + } } else { outputError("CUDA files found in project but CUDA is disabled"); } @@ -1631,10 +1631,194 @@ void ProjectGenerator::outputASMTools(string& projectTemplate) const } } +void ProjectGenerator::outputCUDASourceFiles(StaticList& fileList, string& projectTemplate, string& filterTemplate, + StaticList& foundObjects, set& foundFilters, bool staticOnly, bool sharedOnly, bool bit32Only, bool bit64Only) const +{ + // Constants for CUDA build + const string itemGroup = "\r\n "; + const string itemGroupEnd = "\r\n "; + const string includeClose = "\">"; + const string includeEnd = "\" />"; + const string typeInclude = "\r\n true"; + const string buildConfigsStatic[] = {"Release", "Debug", "ReleaseWinRT", "DebugWinRT"}; + const string buildConfigsShared[] = {"ReleaseDLL", "ReleaseDLLStaticDeps", "DebugDLL", "ReleaseDLLWinRT", + "ReleaseDLLWinRTStaticDeps", "DebugDLLWinRT"}; + + if (fileList.size() > 0) { + string cudaFiles = itemGroup; + string cudaFilesFilt = itemGroup; + string cudaFilesTemp, cudaFilesFiltTemp; + + for (const auto& i : fileList) { + // CUDA custom build entry + cudaFilesTemp = typeInclude; + cudaFilesFiltTemp = typeInclude; + + // Add the fileName + string file = i; + replace(file.begin(), file.end(), '/', '\\'); + cudaFilesTemp += file; + cudaFilesFiltTemp += file; + + // Get object name without path or extension for generated .c file + uint pos = i.rfind('/') + 1; + string objectName = i.substr(pos); + uint pos2 = objectName.rfind('.'); + objectName.resize(pos2); + string outputCFile = "$(IntDir)\\" + objectName + ".ptx.c"; + + // Add the filters Filter + string sourceDir; + m_configHelper.makeFileProjectRelative(m_configHelper.m_rootDirectory, sourceDir); + pos = i.rfind(sourceDir); + pos = (pos == string::npos) ? 0 : pos + sourceDir.length(); + cudaFilesFiltTemp += includeClose; + cudaFilesFiltTemp += filterSource; + uint folderLength = i.rfind('/') - pos; + if (static_cast(folderLength) != -1) { + string folderName = file.substr(pos, folderLength); + folderName = '\\' + folderName; + foundFilters.insert("Source Files" + folderName); + cudaFilesFiltTemp += folderName; + } + cudaFilesFiltTemp += filterEnd; + cudaFilesFiltTemp += typeIncludeEnd; + + // Add CUDA compilation commands + cudaFilesTemp += includeClose; + + // CUDA compilation command: .cu -> .ptx -> .c + cudaFilesTemp += "\r\n \"%CUDA_PATH%\\bin\\nvcc\" -gencode arch=compute_60,code=sm_60 -O2 -m64 -ptx -c -o \"$(IntDir)\\" + objectName + ".ptx\" \"%(FullPath)\" && \"$(ProjectDir)bin2c.exe\" \"$(IntDir)\\" + objectName + ".ptx\" \"" + outputCFile + "\" " + objectName + "_ptx"; + cudaFilesTemp += "\r\n " + outputCFile + ""; + cudaFilesTemp += "\r\n Compiling CUDA file %(Filename)%(Extension)"; + + // Check if this file should be disabled under certain configurations + if (staticOnly || sharedOnly) { + const string* buildConfig = nullptr; + uint configs = 0; + if (staticOnly) { + buildConfig = buildConfigsShared; + configs = sizeof(buildConfigsShared) / sizeof(buildConfigsShared[0]); + } else { + buildConfig = buildConfigsStatic; + configs = sizeof(buildConfigsStatic) / sizeof(buildConfigsStatic[0]); + } + for (uint j = 0; j < configs; j++) { + cudaFilesTemp += excludeConfig; + cudaFilesTemp += buildConfig[j]; + cudaFilesTemp += excludeConfigEnd; + } + } else if (bit32Only || bit64Only) { + cudaFilesTemp += excludeConfigPlatform; + if (bit32Only) { + cudaFilesTemp += "x64"; + } else { + cudaFilesTemp += "Win32"; + } + cudaFilesTemp += excludeConfigEnd; + } + + cudaFilesTemp += typeIncludeEnd; + + // Add to output + cudaFiles += cudaFilesTemp; + cudaFilesFilt += cudaFilesFiltTemp; + } + + cudaFiles += itemGroupEnd; + cudaFilesFilt += itemGroupEnd; + + // Add generated .c files for compilation with explicit dependencies + string cFiles = itemGroup; + string cFilesFilt = itemGroup; + for (const auto& i : fileList) { + uint pos = i.rfind('/') + 1; + string objectName = i.substr(pos); + uint pos2 = objectName.rfind('.'); + objectName.resize(pos2); + string outputCFile = "$(IntDir)\\" + objectName + ".ptx.c"; + string origCuFile = i; + replace(origCuFile.begin(), origCuFile.end(), '/', '\\'); + + // ClCompile entry with explicit dependency + cFiles += "\r\n "; + cFiles += "\r\n " + origCuFile + ""; + + // Check if this file should be disabled under certain configurations + if (staticOnly || sharedOnly) { + const string* buildConfig = nullptr; + uint configs = 0; + if (staticOnly) { + buildConfig = buildConfigsShared; + configs = sizeof(buildConfigsShared) / sizeof(buildConfigsShared[0]); + } else { + buildConfig = buildConfigsStatic; + configs = sizeof(buildConfigsStatic) / sizeof(buildConfigsStatic[0]); + } + for (uint j = 0; j < configs; j++) { + cFiles += "\r\n " + "true"; + } + } else if (bit32Only || bit64Only) { + cFiles += "\r\n " + string("true"); + } + + cFiles += "\r\n "; + + // Filter entry for generated .c file + cFilesFilt += "\r\n "; + cFilesFilt += "\r\n Source Files\\Generated"; + cFilesFilt += "\r\n "; + } + cFiles += itemGroupEnd; + cFilesFilt += itemGroupEnd; + + // Add the Generated filter + foundFilters.insert("Source Files\\Generated"); + + // After add the item groups for CUDA files + string endTag = ""; + uint findPos = projectTemplate.rfind(endTag); + findPos += endTag.length(); + uint findPosFilt = filterTemplate.rfind(endTag); + findPosFilt += endTag.length(); + + // Insert into output file + projectTemplate.insert(findPos, cudaFiles + cFiles); + filterTemplate.insert(findPosFilt, cudaFilesFilt + cFilesFilt); + } +} + void ProjectGenerator::outputCUDATools(string& projectTemplate) const { if (m_configHelper.isCUDAEnabled() && (m_includesCU.size() > 0)) { - // TODO: Add cuda tools + // Copy bin2c.exe to project directory for CUDA compilation + string bin2cContent; + if (!loadFromResourceFile(BIN2C_EXE_ID, bin2cContent)) { + outputError("Failed to load bin2c.exe from resources"); + return; + } + + string bin2cPath = m_configHelper.m_solutionDirectory + "bin2c.exe"; + if (!writeToFile(bin2cPath, bin2cContent, true)) { + outputError("Failed to copy bin2c.exe to project directory"); + return; + } + + // Add CUDA custom build targets for each .cu file + // This will be handled in the modified outputSourceFiles function + // The custom build rules will be added per-file rather than as global tools } }