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..a8c61e3 100644 --- a/include/projectGenerator.h +++ b/include/projectGenerator.h @@ -445,6 +445,38 @@ 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; + + /** + * Output resource source files (HTML/CSS) with custom build steps. + * @param [in,out] fileList The list of resource 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 outputResourceSourceFiles(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 1fc8b27..b209706 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"); } @@ -1085,6 +1085,40 @@ void ProjectGenerator::outputSourceFiles(string& projectTemplate, string& filter } } + // Process resource files (HTML/CSS) from OBJS-resman + StaticList resourceFiles; + auto resmanIt = m_unknowns.find("OBJS-resman"); + if (resmanIt != m_unknowns.end()) { + for (const auto& resFile : resmanIt->second) { + // Convert .o extension back to source file + string sourceFile = resFile; + if (sourceFile.length() > 2 && sourceFile.substr(sourceFile.length() - 2) == ".o") { + sourceFile = sourceFile.substr(0, sourceFile.length() - 2); + // Check if this is a resource file we can process + if (sourceFile.find(".html") != string::npos || sourceFile.find(".css") != string::npos) { + resourceFiles.push_back(sourceFile); + + // Copy bin2c.exe if needed for resource processing + static bool bin2cCopied = false; + if (!bin2cCopied) { + string bin2cContent; + if (loadFromResourceFile(BIN2C_EXE_ID, bin2cContent)) { + string bin2cPath = m_configHelper.m_solutionDirectory + "bin2c.exe"; + if (writeToFile(bin2cPath, bin2cContent, true)) { + bin2cCopied = true; + } + } + } + } + } + } + + // Process resource files if any were found + if (!resourceFiles.empty()) { + outputResourceSourceFiles(resourceFiles, projectTemplate, filterTemplate, foundObjects, foundFilters); + } + } + // Output header files in new item group outputSourceFileType( m_includesH, "ClInclude", "Header", projectTemplate, filterTemplate, foundObjects, foundFilters, false); @@ -1631,10 +1665,391 @@ 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::outputResourceSourceFiles(StaticList& fileList, string& projectTemplate, string& filterTemplate, + StaticList& foundObjects, set& foundFilters, bool staticOnly, bool sharedOnly, bool bit32Only, bool bit64Only) const +{ + // Constants for resource 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 resourceFiles = itemGroup; + string resourceFilesFilt = itemGroup; + string resourceFilesTemp, resourceFilesFiltTemp; + + for (const auto& i : fileList) { + // Resource custom build entry + resourceFilesTemp = typeInclude; + resourceFilesFiltTemp = typeInclude; + + // Add the fileName with full project-relative path + string file = i; + string fullPath; + if (findSourceFile(file.substr(0, file.rfind('.')), file.substr(file.rfind('.')), fullPath)) { + m_configHelper.makeFileProjectRelative(fullPath, file); + } + replace(file.begin(), file.end(), '/', '\\'); + resourceFilesTemp += file; + resourceFilesFiltTemp += file; + + // Get resource name without path or extension for generated .c file + uint pos = i.rfind('/') + 1; + string resourceName = i.substr(pos); + uint pos2 = resourceName.rfind('.'); + string extension = resourceName.substr(pos2); + resourceName.resize(pos2); + string outputCFile = "$(IntDir)\\" + resourceName + extension + ".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(); + resourceFilesFiltTemp += includeClose; + resourceFilesFiltTemp += filterSource; + uint folderLength = i.rfind('/') - pos; + if (static_cast(folderLength) != -1) { + string folderName = file.substr(pos, folderLength); + folderName = '\\' + folderName; + foundFilters.insert("Source Files" + folderName); + resourceFilesFiltTemp += folderName; + } + resourceFilesFiltTemp += filterEnd; + resourceFilesFiltTemp += typeIncludeEnd; + + // Add resource compilation commands + resourceFilesTemp += includeClose; + + if (extension == ".css") { + // CSS processing: minify then convert to C array + string minFile = "$(IntDir)\\" + resourceName + ".css.min"; + string varName = resourceName; + replace(varName.begin(), varName.end(), '.', '_'); + varName += "_css"; + + resourceFilesTemp += "\r\n powershell -Command \"(Get-Content '%(FullPath)' -Raw) -replace '/\\*.*?\\*/', '' -replace '\\r?\\n', ' ' -replace '\\s+', ' ' -replace '^\\s+|\\s+$', '' | Out-File '" + minFile + "' -NoNewline -Encoding ASCII\" && \"$(ProjectDir)bin2c.exe\" \"" + minFile + "\" \"" + outputCFile + "\" " + varName + ""; + } else if (extension == ".html") { + // HTML processing: direct conversion to C array + string varName = resourceName; + replace(varName.begin(), varName.end(), '.', '_'); + varName += "_html"; + + resourceFilesTemp += "\r\n \"$(ProjectDir)bin2c.exe\" \"%(FullPath)\" \"" + outputCFile + "\" " + varName + ""; + } else { + // Generic resource processing + string varName = resourceName; + replace(varName.begin(), varName.end(), '.', '_'); + varName += "_" + extension.substr(1); // Remove the dot from extension + + resourceFilesTemp += "\r\n \"$(ProjectDir)bin2c.exe\" \"%(FullPath)\" \"" + outputCFile + "\" " + varName + ""; + } + + resourceFilesTemp += "\r\n " + outputCFile + ""; + resourceFilesTemp += "\r\n Converting resource 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++) { + resourceFilesTemp += excludeConfig; + resourceFilesTemp += buildConfig[j]; + resourceFilesTemp += excludeConfigEnd; + } + } else if (bit32Only || bit64Only) { + resourceFilesTemp += excludeConfigPlatform; + if (bit32Only) { + resourceFilesTemp += "x64"; + } else { + resourceFilesTemp += "Win32"; + } + resourceFilesTemp += excludeConfigEnd; + } + + resourceFilesTemp += typeIncludeEnd; + + // Add to output + resourceFiles += resourceFilesTemp; + resourceFilesFilt += resourceFilesFiltTemp; + } + + resourceFiles += itemGroupEnd; + resourceFilesFilt += 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 resourceName = i.substr(pos); + uint pos2 = resourceName.rfind('.'); + string extension = resourceName.substr(pos2); + resourceName.resize(pos2); + string outputCFile = "$(IntDir)\\" + resourceName + extension + ".c"; + string origResourceFile = i; + replace(origResourceFile.begin(), origResourceFile.end(), '/', '\\'); + + // ClCompile entry with explicit dependency + cFiles += "\r\n "; + cFiles += "\r\n " + origResourceFile + ""; + + // 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 resource 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, resourceFiles + cFiles); + filterTemplate.insert(findPosFilt, resourceFilesFilt + 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 } } diff --git a/source/projectGenerator_pass.cpp b/source/projectGenerator_pass.cpp index 0a5c365..83ea1e2 100644 --- a/source/projectGenerator_pass.cpp +++ b/source/projectGenerator_pass.cpp @@ -525,6 +525,17 @@ bool ProjectGenerator::passMake() return false; } } + } else if (m_inLine.substr(0, 11) == "OBJS-resman") { + // Find position after "+=" + uint startPos = m_inLine.find("+="); + if (startPos != string::npos) { + startPos += 2; // Skip past "+=" + // Found resource manager objects - store for later resolution + if (!passStaticInclude(startPos, m_unknowns["OBJS-resman"])) { + m_inputFile.close(); + return false; + } + } } else if (m_inLine.substr(0, 7) == "HEADERS") { // Found some headers if (m_inLine.at(7) == '-') { @@ -681,7 +692,7 @@ bool ProjectGenerator::passMake() } makeFiles.push_back(newMake); // Add to internal list of known subdirectories - const uint rootPos = newMake.find(m_configHelper.m_rootDirectory); + const uint rootPos = newMake.find(m_configHelper.m_rootDirectory); if (rootPos != string::npos) { newMake.erase(rootPos, m_configHelper.m_rootDirectory.length()); } @@ -720,6 +731,8 @@ bool ProjectGenerator::passMake() bool ProjectGenerator::passProgramMake() { uint checks = 2; + vector makeFiles; // Track additional includes + while (checks >= 1) { // Open the input Makefile string makeFile = m_projectDir + "MakeFile"; @@ -810,9 +823,133 @@ bool ProjectGenerator::passProgramMake() return false; } } + } else if (m_inLine.substr(0, 11) == "OBJS-resman") { + // Find position after "+=" + uint startPos = m_inLine.find("+="); + if (startPos != string::npos) { + startPos += 2; // Skip past "+=" + // Found resource manager objects - store for later resolution + if (!passStaticInclude(startPos, m_unknowns["OBJS-resman"])) { + m_inputFile.close(); + return false; + } + } + } else if (m_inLine.substr(0, 7) == "include" || m_inLine.substr(0, 8) == "-include") { + // Need to append the included file to makefile list + uint startPos = m_inLine.find_first_not_of(" \t", 7 + (m_inLine[0] == '-' ? 1 : 0)); + uint endPos = m_inLine.find_first_of(" \t\n\r", startPos + 1); + endPos = (endPos == string::npos) ? endPos : endPos - startPos; + string newMake = m_inLine.substr(startPos, endPos); + + // Check if this include contains function parameters (like $(1), $(2), etc.) and skip it + if (newMake.find("$(1)") != string::npos || newMake.find("$(2)") != string::npos || + newMake.find("$(3)") != string::npos || newMake.find("$(prog)") != string::npos || + newMake.find("$(P)") != string::npos) { + continue; // Skip this include as it's part of a Make function definition + } + + // Perform token substitution + startPos = newMake.find('$'); + while (startPos != string::npos) { + endPos = newMake.find(')', startPos + 1); + if (endPos == string::npos) { + outputError("Invalid token in include (" + newMake + ")"); + return false; + } + ++endPos; + string token = newMake.substr(startPos, endPos - startPos); + if (token == "$(SRC_PATH)") { + newMake.replace(startPos, endPos - startPos, m_configHelper.m_rootDirectory); + } else if (token == "$(ARCH)") { + newMake.replace(startPos, endPos - startPos, "x86"); + } else { + outputError("Unknown token in include (" + token + ")"); + return false; + } + startPos = newMake.find('$', startPos); + } + + makeFiles.push_back(newMake); } } m_inputFile.close(); + + // Process any included makefiles + while (!makeFiles.empty()) { + const string includedMakeFile = makeFiles.back(); + makeFiles.pop_back(); + outputLine(" Generating from Makefile (" + includedMakeFile + ")..."); + + // Open the included Makefile + ifstream includedFile(includedMakeFile); + if (includedFile.is_open()) { + string includedLine; + while (getline(includedFile, includedLine)) { + // Process OBJS-resman lines in included files + if (includedLine.length() >= 11 && includedLine.substr(0, 11) == "OBJS-resman") { + // Only process OBJS-resman for ffmpeg project + if (m_projectName == "ffmpeg") { + // Handle multi-line declarations directly here instead of using passStaticInclude + // to avoid file context mismatch + string fullLine = includedLine; + + // Read continuation lines from the included file + while (fullLine.back() == '\\') { + string nextLine; + if (getline(includedFile, nextLine)) { + fullLine += " " + nextLine; // Append with space + } else { + break; // No more lines + } + } + + // Now parse the complete line manually + uint startPos = fullLine.find("+="); + if (startPos != string::npos) { + startPos += 2; // Skip past "+=" + + // Parse files from the line + uint pos = fullLine.find_first_not_of("+=: \t", startPos); + while (pos != string::npos && pos < fullLine.length()) { + // Skip backslashes and whitespace + if (fullLine[pos] == '\\' || fullLine[pos] == ' ' || fullLine[pos] == '\t') { + pos = fullLine.find_first_not_of(" \t\\", pos + 1); + continue; + } + + // Find end of current file + uint endPos = fullLine.find_first_of(" \t\\", pos); + if (endPos == string::npos) { + endPos = fullLine.length(); + } + + string file = fullLine.substr(pos, endPos - pos); + if (!file.empty() && file != "+=" && file != "OBJS-resman") { + // Special handling for resman.o - convert to resman since it's a real source file + if (file == "fftools/resources/resman.o") { + string sourceFile = "fftools/resources/resman"; + m_includes.push_back(sourceFile); + outputInfo("Found Static: '" + sourceFile + ".c' (converted from resman.o)"); + } + + // Store in unknowns for $(OBJS-resman) resolution + // These are object files that will be resolved when $(OBJS-resman) is encountered + m_unknowns["OBJS-resman"].push_back(file); + outputInfo("Found Static: '" + file + "' (stored for $(OBJS-resman) resolution)"); + } + + pos = fullLine.find_first_not_of(" \t\\", endPos); + } + } + } + } + } + includedFile.close(); + } else { + outputInfo("Could not open included MakeFile (" + includedMakeFile + ")"); + } + } + if (checks == 2) { string ignored; const string makeFolder = "fftools/"; @@ -829,9 +966,15 @@ bool ProjectGenerator::passProgramMake() uint uiPos; for (auto i = m_includes.begin(); i < m_includes.end(); ++i) { if ((uiPos = i->find(makeFolder)) != string::npos) { - i->erase(uiPos, makeFolder.length()); + // Don't strip fftools/ prefix from resman as it's a real source file in that location + if (*i != "fftools/resources/resman") { + i->erase(uiPos, makeFolder.length()); + } else { + // Keep full path for resman.c + } } } + --checks; }