不是,而是修改下面的源代码
/******************************************************************************
* SystemC DLL Modifier for VS2015 (C++11) - Ultimate Template API Fix
* Completely fixed template class DLL API marker position issue
* Enhanced to support .cpp file class definitions and comment formats
******************************************************************************/
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
#include <cctype>
#include <windows.h>
// VS2015 Check
#ifdef _MSC_VER
#if _MSC_VER < 1900
#error "This program requires Visual Studio 2015 or later"
#endif
#endif
// Configuration structure
struct Config {
std::string systemcDllApi = "SYSTEMC_DLL_API";
std::string tlmDllApi = "TLM_DLL_API";
std::string includeConfig = "#include \"config.hpp\"";
std::set<std::string> headerExtensions = { ".h", ".hpp", ".hxx" };
std::set<std::string> sourceExtensions = { ".cpp", ".cxx", ".cc" };
std::set<std::string> excludeFiles = { "config.hpp", "Makefile", "CMakeLists.txt" };
std::set<std::string> excludeDirs = { ".git", ".svn", ".vs", "Debug", "Release", "build", "x64", "x86" };
};
// Statistics
struct Statistics {
int totalFiles = 0;
int processedFiles = 0;
int modifiedFiles = 0;
int skippedFiles = 0;
int errorFiles = 0;
};
// String Utilities Class
class StringUtils {
public:
static std::string trim(const std::string& str) {
if (str.empty()) return str;
size_t start = 0;
while (start < str.length() && std::isspace(static_cast<unsigned char>(str[start]))) {
++start;
}
if (start >= str.length()) return "";
size_t end = str.length() - 1;
while (end > start && std::isspace(static_cast<unsigned char>(str[end]))) {
--end;
}
return str.substr(start, end - start + 1);
}
static bool startsWith(const std::string& str, const std::string& prefix) {
if (str.length() < prefix.length()) return false;
return str.compare(0, prefix.length(), prefix) == 0;
}
static bool endsWith(const std::string& str, const std::string& suffix) {
if (str.length() < suffix.length()) return false;
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
}
static bool contains(const std::string& str, const std::string& substr) {
if (substr.empty()) return true;
if (str.empty()) return false;
return str.find(substr) != std::string::npos;
}
static std::string replace(const std::string& str, const std::string& from, const std::string& to) {
if (from.empty() || str.empty()) return str;
std::string result = str;
size_t pos = 0;
while ((pos = result.find(from, pos)) != std::string::npos) {
result.replace(pos, from.length(), to);
pos += to.length();
}
return result;
}
static std::string toLower(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
return result;
}
static std::string toUpper(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char c) { return static_cast<char>(std::toupper(c)); });
return result;
}
static std::string getFileName(const std::string& path) {
if (path.empty()) return "";
size_t pos = path.find_last_of("\\/");
if (pos == std::string::npos) return path;
return path.substr(pos + 1);
}
static std::string getExtension(const std::string& path) {
if (path.empty()) return "";
size_t pos = path.find_last_of(".");
if (pos == std::string::npos) return "";
return path.substr(pos);
}
static std::string getDirectory(const std::string& path) {
if (path.empty()) return "";
size_t pos = path.find_last_of("\\/");
if (pos == std::string::npos) return "";
return path.substr(0, pos);
}
static std::vector<std::string> split(const std::string& str, char delimiter) {
std::vector<std::string> tokens;
if (str.empty()) return tokens;
size_t start = 0;
size_t end = 0;
while ((end = str.find(delimiter, start)) != std::string::npos) {
if (end != start) {
tokens.push_back(str.substr(start, end - start));
}
start = end + 1;
}
if (start < str.length()) {
tokens.push_back(str.substr(start));
}
return tokens;
}
// Check if line is a comment separator
static bool isCommentSeparator(const std::string& str) {
std::string trimmed = trim(str);
return startsWith(trimmed, "// ---") ||
startsWith(trimmed, "/* ---") ||
(contains(trimmed, "---") && (startsWith(trimmed, "//") || startsWith(trimmed, "/*")));
}
// Check if line is a class comment header
static bool isClassCommentHeader(const std::string& str) {
std::string trimmed = trim(str);
return (contains(trimmed, "CLASS :") || contains(trimmed, "class")) &&
(startsWith(trimmed, "//") || startsWith(trimmed, "/*"));
}
};
// File System Utilities Class
class FileSystemUtils {
public:
static bool fileExists(const std::string& path) {
if (path.empty()) return false;
DWORD attrs = GetFileAttributesA(path.c_str());
if (attrs == INVALID_FILE_ATTRIBUTES) return false;
return (attrs & FILE_ATTRIBUTE_DIRECTORY) == 0;
}
static bool directoryExists(const std::string& path) {
if (path.empty()) return false;
DWORD attrs = GetFileAttributesA(path.c_str());
if (attrs == INVALID_FILE_ATTRIBUTES) return false;
return (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
static bool createDirectory(const std::string& path) {
if (path.empty()) return false;
if (directoryExists(path)) return true;
return CreateDirectoryA(path.c_str(), NULL) != 0;
}
static bool createDirectoryRecursive(const std::string& path) {
if (path.empty()) return false;
if (directoryExists(path)) return true;
std::string normalizedPath = path;
std::replace(normalizedPath.begin(), normalizedPath.end(), '/', '\\');
std::vector<std::string> components = StringUtils::split(normalizedPath, '\\');
if (components.empty()) return false;
std::string currentPath;
if (components[0].find(':') != std::string::npos) {
currentPath = components[0] + "\\";
components.erase(components.begin());
}
for (const auto& component : components) {
if (component.empty()) continue;
if (!currentPath.empty() && currentPath.back() != '\\') {
currentPath += "\\";
}
currentPath += component;
if (!createDirectory(currentPath)) {
return false;
}
}
return true;
}
static bool copyFile(const std::string& from, const std::string& to) {
if (from.empty() || to.empty()) return false;
if (!fileExists(from)) return false;
std::string targetDir = StringUtils::getDirectory(to);
if (!targetDir.empty() && !createDirectoryRecursive(targetDir)) {
return false;
}
return ::CopyFileA(from.c_str(), to.c_str(), FALSE) != 0;
}
static bool findFiles(const std::string& directory, std::vector<std::string>& files,
std::vector<std::string>& directories, bool recursive = true) {
if (!directoryExists(directory)) return false;
std::string searchPath = directory + "\\*";
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (strcmp(findData.cFileName, ".") == 0 || strcmp(findData.cFileName, "..") == 0) {
continue;
}
std::string fullPath = directory + "\\" + findData.cFileName;
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
std::string dirName = findData.cFileName;
if (isDirectoryExcluded(dirName)) continue;
directories.push_back(fullPath);
if (recursive) {
findFiles(fullPath, files, directories, recursive);
}
}
else {
files.push_back(fullPath);
}
} while (FindNextFileA(hFind, &findData) != 0);
FindClose(hFind);
return true;
}
private:
static bool isDirectoryExcluded(const std::string& dirName) {
static std::set<std::string> excludedDirs = {
".git", ".svn", ".vs", "Debug", "Release", "build", "x64", "x86", "obj", "bin"
};
std::string lowerName = StringUtils::toLower(dirName);
return excludedDirs.find(lowerName) != excludedDirs.end();
}
};
// Main Processor Class - Ultimate Template API Fix
class SystemCDLLModifier {
private:
Config config;
Statistics stats;
bool dryRun;
bool createBackup;
std::string backupDir;
public:
SystemCDLLModifier(bool dryRunMode = false, bool backup = false)
: dryRun(dryRunMode), createBackup(backup) {}
bool processDirectory(const std::string& sourceDir) {
std::cout << "Processing directory: " << sourceDir << std::endl;
if (!FileSystemUtils::directoryExists(sourceDir)) {
std::cerr << "Error: Directory does not exist: " << sourceDir << std::endl;
return false;
}
// Create backup
if (createBackup && !dryRun) {
std::cout << "\nCreating backup..." << std::endl;
if (!createBackupDirectory(sourceDir)) {
std::cout << "Backup creation had issues!" << std::endl;
std::cout << "Do you want to continue without backup? (y/n): ";
char response;
std::cin >> response;
if (response != 'y' && response != 'Y') {
return false;
}
}
}
// Process files
std::vector<std::string> files;
std::vector<std::string> directories;
if (!FileSystemUtils::findFiles(sourceDir, files, directories, true)) {
std::cerr << "Failed to enumerate files" << std::endl;
return false;
}
stats.totalFiles = static_cast<int>(files.size());
std::cout << "Found " << stats.totalFiles << " files to process" << std::endl;
for (int i = 0; i < stats.totalFiles; ++i) {
processFile(files[i]);
if ((i + 1) % 10 == 0 || (i + 1) == stats.totalFiles) {
int percent = (i + 1) * 100 / stats.totalFiles;
std::cout << "Processing: " << (i + 1) << "/" << stats.totalFiles
<< " files (" << percent << "%)" << std::endl;
}
}
// Generate config.hpp
if (!dryRun) {
generateConfigFile(sourceDir);
}
return true;
}
const Statistics& getStatistics() const { return stats; }
const std::string& getBackupDir() const { return backupDir; }
private:
void processFile(const std::string& filePath) {
if (!FileSystemUtils::fileExists(filePath)) {
stats.skippedFiles++;
return;
}
std::string filename = StringUtils::getFileName(filePath);
std::string ext = StringUtils::getExtension(filePath);
// Check excluded files
if (config.excludeFiles.find(StringUtils::toLower(filename)) != config.excludeFiles.end()) {
stats.skippedFiles++;
return;
}
// Check extension
bool isHeader = config.headerExtensions.find(ext) != config.headerExtensions.end();
bool isSource = config.sourceExtensions.find(ext) != config.sourceExtensions.end();
if (!isHeader && !isSource) {
stats.skippedFiles++;
return;
}
stats.processedFiles++;
if (isHeader) {
processHeaderFile(filePath);
}
else {
processSourceFile(filePath);
}
}
void processHeaderFile(const std::string& filePath) {
std::vector<std::string> lines;
if (!readFile(filePath, lines)) {
stats.errorFiles++;
return;
}
bool isSystemcFile = false;
bool isTlmFile = false;
std::string filename = StringUtils::getFileName(filePath);
// Check file type
if (filename == "systemc.h" || StringUtils::startsWith(filename, "sc_") ||
StringUtils::contains(StringUtils::toLower(filename), "vcd") ||
StringUtils::contains(StringUtils::toLower(filename), "trace")) {
isSystemcFile = true;
}
else if (filename == "tlm.h" || StringUtils::contains(StringUtils::toLower(filename), "tlm")) {
isTlmFile = true;
}
else {
// Check content
for (const auto& line : lines) {
std::string trimmed = StringUtils::trim(line);
if (StringUtils::contains(trimmed, "namespace sc_core") ||
StringUtils::contains(trimmed, "SC_MODULE") ||
StringUtils::contains(trimmed, "class sc_") ||
StringUtils::contains(trimmed, "class vcd_") ||
StringUtils::contains(trimmed, "vcd_trace")) {
isSystemcFile = true;
break;
}
else if (StringUtils::contains(trimmed, "namespace tlm") ||
StringUtils::contains(trimmed, "class tlm_")) {
isTlmFile = true;
break;
}
}
}
if (!isSystemcFile && !isTlmFile) {
stats.skippedFiles++;
return;
}
std::string dllApi = isTlmFile ? config.tlmDllApi : config.systemcDllApi;
bool modified = false;
// Check if config.hpp is already included
bool hasConfigInclude = false;
for (size_t i = 0; i < lines.size(); ++i) {
std::string trimmed = StringUtils::trim(lines[i]);
if (StringUtils::contains(trimmed, "#include \"config.hpp\"") ||
StringUtils::contains(trimmed, "#include <config.hpp>")) {
hasConfigInclude = true;
break;
}
}
// Add config.hpp include
if (!hasConfigInclude) {
bool inserted = false;
for (size_t i = 0; i < lines.size(); ++i) {
std::string trimmed = StringUtils::trim(lines[i]);
if (StringUtils::startsWith(trimmed, "#include")) {
lines.insert(lines.begin() + i, config.includeConfig);
inserted = true;
modified = true;
break;
}
}
if (!inserted) {
lines.insert(lines.begin(), config.includeConfig);
modified = true;
}
}
// Process class declarations and templates with enhanced pattern matching
for (size_t i = 0; i < lines.size(); ++i) {
std::string line = lines[i];
std::string trimmed = StringUtils::trim(line);
// Skip preprocessor directives and comments
if (StringUtils::startsWith(trimmed, "#") ||
StringUtils::startsWith(trimmed, "//") ||
StringUtils::startsWith(trimmed, "/*")) {
continue;
}
// Process regular classes (including those with comment headers)
if (isClassDeclarationLine(trimmed)) {
if (!StringUtils::contains(trimmed, config.systemcDllApi) &&
!StringUtils::contains(trimmed, config.tlmDllApi)) {
// Check if this class has a comment header above it
if (i > 0 && hasCommentHeader(lines, i)) {
// Find the start of the comment block
size_t commentStart = findCommentBlockStart(lines, i);
if (commentStart != std::string::npos && commentStart < i) {
// Insert API after the comment block, before the class declaration
lines[i] = addAPIToClassDeclaration(trimmed, dllApi);
modified = true;
}
}
else {
// No comment header, just add API to the class line
lines[i] = addAPIToClassDeclaration(trimmed, dllApi);
modified = true;
}
}
}
// ULTIMATE FIX: Template class API placement with inheritance support
if (isTemplateClassDeclaration(trimmed)) {
modified = ultimateTemplateFix(lines, i, dllApi, filePath) || modified;
}
}
if (modified) {
if (dryRun) {
std::cout << "[DRY RUN] Would modify header: " << filePath << std::endl;
stats.modifiedFiles++;
}
else {
if (writeFile(filePath, lines)) {
std::cout << "Modified header: " << filePath << std::endl;
stats.modifiedFiles++;
}
else {
std::cerr << "Failed to write header: " << filePath << std::endl;
stats.errorFiles++;
}
}
}
}
// Check if line is a class declaration
bool isClassDeclarationLine(const std::string& line) {
std::string trimmed = StringUtils::trim(line);
// Match patterns like:
// class class_name
// class class_name {
// class class_name :
if (StringUtils::startsWith(trimmed, "class ") &&
!StringUtils::contains(trimmed, "template")) {
// Extract class name part (after "class ")
size_t classPos = trimmed.find("class ");
size_t afterClass = classPos + 6;
if (afterClass >= trimmed.length()) return false;
std::string afterClassStr = trimmed.substr(afterClass);
StringUtils::trim(afterClassStr);
// Check if it's a real class name (not a template parameter)
if (afterClassStr.empty()) return false;
// Exclude single-letter template parameters
if (afterClassStr.length() == 1 &&
(afterClassStr[0] == 'T' || afterClassStr[0] == 'U' ||
afterClassStr[0] == 'V' || afterClassStr[0] == 'W')) {
return false;
}
return true;
}
return false;
}
// Check if line is a template class declaration
bool isTemplateClassDeclaration(const std::string& line) {
std::string trimmed = StringUtils::trim(line);
// Match patterns like:
// template <class T> class class_name
// template <typename T> class class_name
// template <class T> class class_name :
if (StringUtils::startsWith(trimmed, "template") &&
(StringUtils::contains(trimmed, "class") || StringUtils::contains(trimmed, "typename")) &&
StringUtils::contains(trimmed, "class ")) {
// Check if it's a template parameter declaration (like template<class T>)
if (isTemplateParameterDeclaration(trimmed)) {
return false;
}
return true;
}
return false;
}
// Check if line is a template parameter declaration
bool isTemplateParameterDeclaration(const std::string& line) {
std::string trimmed = StringUtils::trim(line);
// Template parameter declarations end with > and don't have a second class keyword
if (!StringUtils::contains(trimmed, ">")) return false;
// Check if it's a simple template parameter like template<class T>
size_t templatePos = trimmed.find("template");
size_t angleBracketPos = trimmed.find(">", templatePos);
if (angleBracketPos == std::string::npos) return false;
// Check if there's content after the > that indicates it's a real class
std::string afterAngleBracket = trimmed.substr(angleBracketPos + 1);
StringUtils::trim(afterAngleBracket);
// If there's no content after >, it's likely a template parameter declaration
if (afterAngleBracket.empty()) return true;
// If there's content but it doesn't contain "class", it's probably not a class declaration
return !StringUtils::contains(afterAngleBracket, "class");
}
// Check if class has a comment header above it
bool hasCommentHeader(const std::vector<std::string>& lines, size_t currentLine) {
if (currentLine == 0) return false;
// Check previous lines for comment patterns
for (int i = static_cast<int>(currentLine) - 1; i >= 0 && i >= static_cast<int>(currentLine) - 10; --i) {
std::string line = lines[i];
std::string trimmed = StringUtils::trim(line);
if (trimmed.empty()) continue;
// Check for comment separators or class comment headers
if (StringUtils::isCommentSeparator(trimmed) ||
StringUtils::isClassCommentHeader(trimmed)) {
return true;
}
// If we hit a non-comment, non-empty line, stop searching
if (!StringUtils::startsWith(trimmed, "//") &&
!StringUtils::startsWith(trimmed, "/*") &&
!trimmed.empty()) {
break;
}
}
return false;
}
// Find the start of a comment block before a class declaration
size_t findCommentBlockStart(const std::vector<std::string>& lines, size_t currentLine) {
if (currentLine == 0) return std::string::npos;
for (int i = static_cast<int>(currentLine) - 1; i >= 0; --i) {
std::string line = lines[i];
std::string trimmed = StringUtils::trim(line);
if (trimmed.empty()) continue;
// Look for the start of the comment block (first comment line)
if (StringUtils::startsWith(trimmed, "//") ||
StringUtils::startsWith(trimmed, "/*")) {
// Check if this is the first comment in the block
if (i == 0 ||
!StringUtils::startsWith(StringUtils::trim(lines[i - 1]), "//") &&
!StringUtils::startsWith(StringUtils::trim(lines[i - 1]), "/*")) {
return i;
}
}
else {
// Non-comment line, stop searching
break;
}
}
return std::string::npos;
}
// Add API to class declaration (handles inheritance)
std::string addAPIToClassDeclaration(const std::string& line, const std::string& dllApi) {
std::string result = line;
// Find "class " position
size_t classPos = result.find("class ");
if (classPos == std::string::npos) return line;
// Position after "class "
size_t afterClass = classPos + 6;
while (afterClass < result.length() && std::isspace(result[afterClass])) {
afterClass++;
}
if (afterClass >= result.length()) return line;
// Insert API after "class " but before the class name
result = result.substr(0, afterClass) + dllApi + " " + result.substr(afterClass);
return result;
}
void processSourceFile(const std::string& filePath) {
std::vector<std::string> lines;
if (!readFile(filePath, lines)) {
stats.errorFiles++;
return;
}
bool isSystemcFile = false;
bool isTlmFile = false;
std::string filename = StringUtils::getFileName(filePath);
// Check file type
if (StringUtils::startsWith(filename, "sc_") ||
StringUtils::contains(filename, "tlm") ||
StringUtils::contains(filename, "vcd") ||
StringUtils::contains(filename, "trace")) {
isSystemcFile = true;
}
else {
// Check content for SystemC/TLM indicators
for (const auto& line : lines) {
std::string trimmed = StringUtils::trim(line);
if (StringUtils::contains(trimmed, "namespace sc_core") ||
StringUtils::contains(trimmed, "SC_MODULE") ||
StringUtils::contains(trimmed, "class sc_") ||
StringUtils::contains(trimmed, "sc_vcd_trace") ||
StringUtils::contains(trimmed, "vcd_trace") ||
StringUtils::contains(trimmed, "sc_main")) {
isSystemcFile = true;
break;
}
else if (StringUtils::contains(trimmed, "namespace tlm") ||
StringUtils::contains(trimmed, "class tlm_")) {
isTlmFile = true;
break;
}
}
}
if (!isSystemcFile && !isTlmFile) {
stats.skippedFiles++;
return;
}
std::string dllApi = isTlmFile ? config.tlmDllApi : config.systemcDllApi;
bool modified = false;
// Check if config.hpp is already included
bool hasConfigInclude = false;
for (size_t i = 0; i < lines.size(); ++i) {
std::string trimmed = StringUtils::trim(lines[i]);
if (StringUtils::contains(trimmed, "#include \"config.hpp\"") ||
StringUtils::contains(trimmed, "#include <config.hpp>")) {
hasConfigInclude = true;
break;
}
}
// Add config.hpp include to source files
if (!hasConfigInclude) {
bool inserted = false;
for (size_t i = 0; i < lines.size(); ++i) {
std::string trimmed = StringUtils::trim(lines[i]);
if (StringUtils::startsWith(trimmed, "#include")) {
lines.insert(lines.begin() + i, config.includeConfig);
inserted = true;
modified = true;
break;
}
}
if (!inserted) {
// If no #include found, add at the beginning
lines.insert(lines.begin(), config.includeConfig);
modified = true;
}
}
// Process class definitions in .cpp files
for (size_t i = 0; i < lines.size(); ++i) {
std::string line = lines[i];
std::string trimmed = StringUtils::trim(line);
// Skip preprocessor directives and comments
if (StringUtils::startsWith(trimmed, "#") ||
StringUtils::startsWith(trimmed, "//") ||
StringUtils::startsWith(trimmed, "/*")) {
continue;
}
// Process class member function definitions in .cpp files
if (isClassMemberFunctionDefinition(trimmed)) {
modified = processClassMemberFunction(lines, i, dllApi, filePath) || modified;
}
// Process template specializations in .cpp files
if (isTemplateSpecialization(trimmed)) {
modified = processTemplateSpecialization(lines, i, dllApi, filePath) || modified;
}
// Process static member definitions in .cpp files
if (isStaticMemberDefinition(trimmed)) {
modified = processStaticMemberDefinition(lines, i, dllApi, filePath) || modified;
}
}
if (modified) {
if (dryRun) {
std::cout << "[DRY RUN] Would modify source: " << filePath << std::endl;
stats.modifiedFiles++;
}
else {
if (writeFile(filePath, lines)) {
std::cout << "Modified source: " << filePath << std::endl;
stats.modifiedFiles++;
}
else {
std::cerr << "Failed to write source: " << filePath << std::endl;
stats.errorFiles++;
}
}
}
}
// Check if line is a class member function definition
bool isClassMemberFunctionDefinition(const std::string& line) {
std::string trimmed = StringUtils::trim(line);
// Pattern: return_type class_name::function_name
if (!StringUtils::contains(trimmed, "::")) return false;
if (!StringUtils::contains(trimmed, "(")) return false;
if (!StringUtils::contains(trimmed, ")")) return false;
if (StringUtils::contains(trimmed, ";")) return false; // Not a declaration
// Check if it's a SystemC related class
std::vector<std::string> systemcClasses = {
"sc_", "tlm_", "vcd_", "wif_", "signal_", "module_", "port_"
};
for (const auto& className : systemcClasses) {
if (StringUtils::contains(trimmed, className) &&
StringUtils::contains(trimmed, "::")) {
return true;
}
}
return false;
}
// Process class member function definition
bool processClassMemberFunction(std::vector<std::string>& lines, size_t currentLine,
const std::string& dllApi, const std::string& filePath) {
std::string line = lines[currentLine];
std::string trimmed = StringUtils::trim(line);
// Check if already has API
if (StringUtils::contains(trimmed, dllApi)) {
return false;
}
// Add API to function definition
std::string fixedLine = addAPIToFunctionDefinition(trimmed, dllApi);
if (fixedLine != line) {
lines[currentLine] = fixedLine;
std::cout << "ADDED API to function definition in " << filePath << ":\n";
std::cout << " BEFORE: " << trimmed << "\n";
std::cout << " AFTER: " << fixedLine << std::endl;
return true;
}
return false;
}
// Check if line is a template specialization
bool isTemplateSpecialization(const std::string& line) {
std::string trimmed = StringUtils::trim(line);
// Pattern: template class ClassName<Args>;
if (!StringUtils::contains(trimmed, "template class")) return false;
if (!StringUtils::contains(trimmed, ";")) return false;
// Check if it's a SystemC related class
std::vector<std::string> systemcClasses = {
"sc_", "tlm_", "vcd_", "signal_"
};
for (const auto& className : systemcClasses) {
if (StringUtils::contains(trimmed, className)) {
return true;
}
}
return false;
}
// Process template specialization
bool processTemplateSpecialization(std::vector<std::string>& lines, size_t currentLine,
const std::string& dllApi, const std::string& filePath) {
std::string line = lines[currentLine];
std::string trimmed = StringUtils::trim(line);
// Check if already has API
if (StringUtils::contains(trimmed, dllApi)) {
return false;
}
// Add API to template specialization
std::string fixedLine = addAPIToTemplateSpecialization(trimmed, dllApi);
if (fixedLine != line) {
lines[currentLine] = fixedLine;
std::cout << "ADDED API to template specialization in " << filePath << ":\n";
std::cout << " BEFORE: " << trimmed << "\n";
std::cout << " AFTER: " << fixedLine << std::endl;
return true;
}
return false;
}
// Check if line is a static member definition
bool isStaticMemberDefinition(const std::string& line) {
std::string trimmed = StringUtils::trim(line);
// Pattern: type class_name::member = value;
if (!StringUtils::contains(trimmed, "::")) return false;
if (!StringUtils::contains(trimmed, "=")) return false;
if (!StringUtils::contains(trimmed, ";")) return false;
// Check if it's a SystemC related class
std::vector<std::string> systemcClasses = {
"sc_", "tlm_", "vcd_", "signal_"
};
for (const auto& className : systemcClasses) {
if (StringUtils::contains(trimmed, className) &&
StringUtils::contains(trimmed, "::")) {
return true;
}
}
return false;
}
// Process static member definition
bool processStaticMemberDefinition(std::vector<std::string>& lines, size_t currentLine,
const std::string& dllApi, const std::string& filePath) {
std::string line = lines[currentLine];
std::string trimmed = StringUtils::trim(line);
// Check if already has API
if (StringUtils::contains(trimmed, dllApi)) {
return false;
}
// Add API to static member definition
std::string fixedLine = addAPIToStaticMemberDefinition(trimmed, dllApi);
if (fixedLine != line) {
lines[currentLine] = fixedLine;
std::cout << "ADDED API to static member definition in " << filePath << ":\n";
std::cout << " BEFORE: " << trimmed << "\n";
std::cout << " AFTER: " << fixedLine << std::endl;
return true;
}
return false;
}
// Add API to function definition
std::string addAPIToFunctionDefinition(const std::string& line, const std::string& dllApi) {
// Add API at the beginning of function definition
return dllApi + " " + line;
}
// Add API to template specialization
std::string addAPIToTemplateSpecialization(const std::string& line, const std::string& dllApi) {
// Pattern: template class ClassName<Args>;
// Change to: template class SYSTEMC_DLL_API ClassName<Args>;
return StringUtils::replace(line, "template class", "template class " + dllApi);
}
// Add API to static member definition
std::string addAPIToStaticMemberDefinition(const std::string& line, const std::string& dllApi) {
// Add API at the beginning of static member definition
return dllApi + " " + line;
}
// ULTIMATE FIX: Template class API placement for header files with inheritance support
bool ultimateTemplateFix(std::vector<std::string>& lines, size_t currentLine,
const std::string& dllApi, const std::string& filePath) {
std::string line = lines[currentLine];
std::string trimmed = StringUtils::trim(line);
// Debug output
std::cout << "DEBUG Processing template: " << trimmed << std::endl;
// Basic checks
if (!StringUtils::contains(trimmed, "template") ||
(!StringUtils::contains(trimmed, "class") && !StringUtils::contains(trimmed, "typename"))) {
return false;
}
// Skip if already has API
if (StringUtils::contains(trimmed, dllApi)) {
std::cout << "DEBUG: Already has API, skipping" << std::endl;
return false;
}
// Check if this is a template parameter declaration (like template<class T>)
if (isTemplateParameterDeclaration(trimmed)) {
std::cout << "DEBUG: Skipping template parameter declaration" << std::endl;
return false;
}
// For all other cases, add API
std::string fixedLine = addAPIToTemplateClass(trimmed, dllApi);
if (fixedLine != line) {
lines[currentLine] = fixedLine;
std::cout << "SUCCESS: Added API to template in " << filePath << ":\n";
std::cout << " BEFORE: " << trimmed << "\n";
std::cout << " AFTER: " << fixedLine << std::endl;
return true;
}
return false;
}
// Add API to template class (handles inheritance)
std::string addAPIToTemplateClass(const std::string& line, const std::string& dllApi) {
std::string result = line;
// Find the class keyword after template
size_t templatePos = result.find("template");
if (templatePos == std::string::npos) return line;
// Find the second "class" keyword (the actual class declaration)
size_t firstClassPos = result.find("class", templatePos);
if (firstClassPos == std::string::npos) {
firstClassPos = result.find("typename", templatePos);
if (firstClassPos == std::string::npos) return line;
}
// Find the actual class declaration (second "class" keyword)
size_t secondClassPos = result.find("class", firstClassPos + 5);
if (secondClassPos == std::string::npos) {
// If no second class, it might be a template alias or other construct
return line;
}
// Position after second "class"
size_t afterClass = secondClassPos + 5;
while (afterClass < result.length() && std::isspace(result[afterClass])) {
afterClass++;
}
if (afterClass >= result.length()) return line;
// Insert API after the second "class" keyword
result = result.substr(0, afterClass) + dllApi + " " + result.substr(afterClass);
return result;
}
void generateConfigFile(const std::string& outputDir) {
std::string configPath = outputDir + "\\config.hpp";
if (FileSystemUtils::fileExists(configPath)) {
std::cout << "config.hpp already exists, skipping generation" << std::endl;
return;
}
std::string content =
"#ifndef __CONFIG_HPP__\r\n"
"#define __CONFIG_HPP__\r\n"
"\r\n"
"#undef SYSTEMC_DLL_API\r\n"
"#undef TLM_DLL_API\r\n"
"\r\n"
"// C++11 Configuration for VS2015\r\n"
"#if defined(_MSC_VER) && (_MSC_VER < 1900)\r\n"
" #error \"Visual Studio 2015 (VC++ 14.0) or later is required for C++11 support\"\r\n"
"#endif\r\n"
"\r\n"
"// DLL Configuration\r\n"
"#define SYSTEMC_DLL // Enable DLL support\r\n"
"#define SYSTEMC_DLL_EXPORT // Define this to export DLL symbols\r\n"
"\r\n"
"#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS)\r\n"
" #ifdef SYSTEMC_DLL\r\n"
" #ifdef SYSTEMC_DLL_EXPORT\r\n"
" #define SYSTEMC_DLL_API __declspec(dllexport)\r\n"
" #else\r\n"
" #define SYSTEMC_DLL_API __declspec(dllimport)\r\n"
" #endif\r\n"
"\r\n"
" // Disable VS2015 warnings for DLL exports\r\n"
" #ifdef _MSC_VER\r\n"
" #pragma warning(push)\r\n"
" #pragma warning(disable: 4251) // class needs dll-interface\r\n"
" #pragma warning(disable: 4275) // non dll-interface base class\r\n"
" #endif\r\n"
"\r\n"
" #else\r\n"
" #define SYSTEMC_DLL_API\r\n"
" #endif\r\n"
"#else\r\n"
" #define SYSTEMC_DLL_API\r\n"
"#endif\r\n"
"\r\n"
"// TLM DLL API definition\r\n"
"#define TLM_DLL_API SYSTEMC_DLL_API\r\n"
"\r\n"
"// C++11 standard library includes\r\n"
"#include <cstdint>\r\n"
"#include <memory>\r\n"
"#include <string>\r\n"
"#include <vector>\r\n"
"\r\n"
"#endif // __CONFIG_HPP__\r\n";
std::ofstream file(configPath, std::ios::binary);
if (file.is_open()) {
file.write(content.c_str(), content.length());
file.close();
std::cout << "Generated config.hpp at: " << configPath << std::endl;
}
else {
std::cerr << "Failed to generate config.hpp" << std::endl;
}
}
bool readFile(const std::string& filePath, std::vector<std::string>& lines) {
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Cannot open file for reading: " << filePath << std::endl;
return false;
}
lines.clear();
std::string line;
while (std::getline(file, line)) {
// Handle Windows line endings
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
lines.push_back(line);
}
if (file.bad()) {
std::cerr << "Error reading file: " << filePath << std::endl;
file.close();
return false;
}
file.close();
return true;
}
bool writeFile(const std::string& filePath, const std::vector<std::string>& lines) {
std::ofstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Cannot open file for writing: " << filePath << std::endl;
return false;
}
for (const auto& line : lines) {
file << line << "\r\n";
}
if (file.bad()) {
std::cerr << "Error writing file: " << filePath << std::endl;
file.close();
return false;
}
file.close();
return true;
}
bool createBackupDirectory(const std::string& sourceDir) {
if (!FileSystemUtils::directoryExists(sourceDir)) {
std::cerr << "Source directory does not exist: " << sourceDir << std::endl;
return false;
}
// Generate timestamped backup directory name
SYSTEMTIME st;
GetLocalTime(&st);
char timeBuffer[256];
sprintf_s(timeBuffer, "SystemC_Backup_%04d%02d%02d_%02d%02d%02d",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
backupDir = timeBuffer;
std::cout << "Creating backup: " << backupDir << std::endl;
// Create backup directory
if (!FileSystemUtils::createDirectoryRecursive(backupDir)) {
std::cerr << "Failed to create backup directory: " << backupDir << std::endl;
return false;
}
// Copy files
std::vector<std::string> files;
std::vector<std::string> directories;
if (!FileSystemUtils::findFiles(sourceDir, files, directories, true)) {
std::cerr << "Failed to enumerate files for backup" << std::endl;
return false;
}
int copiedFiles = 0;
int failedFiles = 0;
int totalFiles = static_cast<int>(files.size());
std::cout << "Found " << totalFiles << " files to backup" << std::endl;
for (int i = 0; i < totalFiles; ++i) {
const auto& file = files[i];
// Calculate relative path
std::string relativePath = getRelativePath(sourceDir, file);
if (relativePath.empty()) {
failedFiles++;
continue;
}
std::string targetPath = backupDir + "\\" + relativePath;
if (FileSystemUtils::copyFile(file, targetPath)) {
copiedFiles++;
}
else {
failedFiles++;
std::cerr << "Failed to copy: " << file << std::endl;
}
// Show progress
if ((i + 1) % 100 == 0 || (i + 1) == totalFiles) {
int percent = (i + 1) * 100 / totalFiles;
std::cout << "Backup progress: " << (i + 1) << "/" << totalFiles
<< " files (" << percent << "%)" << std::endl;
}
}
std::cout << "\nBackup completed:" << std::endl;
std::cout << " Successfully copied: " << copiedFiles << " files" << std::endl;
std::cout << " Failed: " << failedFiles << " files" << std::endl;
std::cout << " Backup location: " << backupDir << std::endl;
if (failedFiles > 0) {
std::cout << "WARNING: " << failedFiles << " files failed to backup!" << std::endl;
}
return failedFiles == 0;
}
std::string getRelativePath(const std::string& baseDir, const std::string& fullPath) {
if (fullPath.find(baseDir) != 0) {
return fullPath;
}
std::string relative = fullPath.substr(baseDir.length());
// Remove leading path separators
while (!relative.empty() && (relative[0] == '\\' || relative[0] == '/')) {
relative = relative.substr(1);
}
return relative;
}
};
// Help information
void printHelp() {
std::cout << R"(
========================================================================
SystemC DLL Modifier for VS2015 (C++11) - Ultimate Template API Fix
================================================================
ENHANCED VERSION: Now supports .cpp file class definitions and comment headers!
ULTIMATE FIX:
- Completely fixed template class DLL API placement error
- Now supports .cpp file class definitions
- Handles comment headers above class declarations
- Supports template class inheritance patterns
================================================================
Usage: systemc_modifier_ultimate.exe <SystemC_directory> [options]
Options:
/dryrun Dry run mode (test without modifying files)
/backup Create backup directory before modifications
/help Display this help information
/force Force processing even if backup fails
Examples:
systemc_modifier_ultimate.exe C:\systemc-2.3.1a
systemc_modifier_ultimate.exe C:\systemc-2.3.1a /dryrun
systemc_modifier_ultimate.exe C:\systemc-2.3.1a /backup
systemc_modifier_ultimate.exe /help
NEW FEATURES:
1. Support for .cpp file class member function definitions
2. Support for template specializations in .cpp files
3. Support for static member definitions in .cpp files
4. Enhanced pattern matching for comment headers
5. Improved template class API placement
Supported Patterns in .cpp files:
Pattern 1: Class member function definitions
void sc_vcd_trace::write_comment(const std::string& comment) {
// implementation
}
Pattern 2: Template specializations
template class vcd_T_trace<bool>;
template class vcd_T_trace<sc_dt::sc_logic>;
Pattern 3: Static member definitions
int sc_vcd_trace::instance_count = 0;
Fixed Output for .cpp files:
SYSTEMC_DLL_API void sc_vcd_trace::write_comment(const std::string& comment) {
// implementation
}
template class SYSTEMC_DLL_API vcd_T_trace<bool>;
template class SYSTEMC_DLL_API vcd_T_trace<sc_dt::sc_logic>;
SYSTEMC_DLL_API int sc_vcd_trace::instance_count = 0;
Supported Patterns in .h files:
Pattern 1: Comment headers
// ----------------------------------------------------------------------------
// CLASS : vcd_trace
//
// Base class for VCD traces.
// ----------------------------------------------------------------------------
class vcd_trace
{
Pattern 2: Template class inheritance
template <class T>
class vcd_T_trace : public vcd_trace
{
Fixed Output for .h files:
// ----------------------------------------------------------------------------
// CLASS : vcd_trace
//
// Base class for VCD traces.
// ----------------------------------------------------------------------------
class SYSTEMC_DLL_API vcd_trace
{
template <class T>
class SYSTEMC_DLL_API vcd_T_trace : public vcd_trace
{
Enhanced Features:
1. Automatically add #include "config.hpp" to SystemC headers AND source files
2. Add SYSTEMC_DLL_API or TLM_DLL_API export macros to classes
3. Generate config.hpp configuration file
4. Create timestamped backup directories
5. Process .h and .cpp files recursively
6. Skip build directories and version control directories
7. Retry mechanism for file operations
8. Detailed progress reporting
9. ULTIMATE template API placement fix
10. .cpp file class definition support
11. Comment header support
12. Template inheritance support
Important Notes:
1. Always backup your important code before making modifications!
2. Test with /dryrun first to see what will be modified
3. The program will ask for confirmation if backup fails
4. Generated config.hpp includes proper warning suppression
5. Run as Administrator for system-protected directories
================================================================
)" << std::endl;
}
// Print statistics
void printStatistics(const Statistics& stats, bool dryRun, const std::string& backupDir) {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << "PROCESSING COMPLETED\n";
std::cout << std::string(60, '=') << "\n";
std::cout << "Total files: " << stats.totalFiles << "\n";
std::cout << "Processed files: " << stats.processedFiles << "\n";
std::cout << "Modified files: " << stats.modifiedFiles << "\n";
std::cout << "Skipped files: " << stats.skippedFiles << "\n";
std::cout << "Error files: " << stats.errorFiles << "\n";
if (!backupDir.empty()) {
std::cout << "\nBackup created: " << backupDir << "\n";
}
if (dryRun) {
std::cout << "\nMODE: DRY RUN - No files were actually modified\n";
std::cout << "To actually modify files, run without /dryrun option\n";
}
std::cout << std::string(60, '=') << "\n";
}
// Main function
int main(int argc, char* argv[]) {
std::cout << "========================================================================\n";
std::cout << " SystemC DLL Modifier for VS2015 (C++11) - Ultimate Template API Fix\n";
std::cout << " ================================================================\n";
std::cout << " Enhanced Version: Now supports .cpp file class definitions!\n";
std::cout << " Completely fixed template class DLL API position error\n";
std::cout << "========================================================================\n\n";
if (argc < 2) {
printHelp();
return 1;
}
std::string sourceDir = argv[1];
bool dryRun = false;
bool createBackup = false;
bool forceMode = false;
// Parse command line arguments
for (int i = 2; i < argc; ++i) {
std::string arg = argv[i];
std::string lowerArg = arg;
std::transform(lowerArg.begin(), lowerArg.end(), lowerArg.begin(), ::tolower);
if (lowerArg == "/dryrun" || lowerArg == "-dryrun" || lowerArg == "/d") {
dryRun = true;
}
else if (lowerArg == "/backup" || lowerArg == "-backup" || lowerArg == "/b") {
createBackup = true;
}
else if (lowerArg == "/help" || lowerArg == "-help" || lowerArg == "/h" || lowerArg == "/?") {
printHelp();
return 0;
}
else if (lowerArg == "/force" || lowerArg == "-force" || lowerArg == "/f") {
forceMode = true;
}
else {
std::cout << "Unknown option: " << arg << "\n";
std::cout << "Use /help for usage information\n";
return 1;
}
}
// Display mode information
std::cout << "Mode: " << (dryRun ? "Dry Run (no modifications)" :
createBackup ? "Normal with Backup" : "Normal") << "\n";
std::cout << "Target: " << sourceDir << "\n";
std::cout << "Force mode: " << (forceMode ? "Yes" : "No") << "\n";
std::cout << "C++ Standard: C++11\n";
std::cout << "Compiler: Visual Studio 2015\n";
std::cout << "Fix: Ultimate template API placement fix\n";
std::cout << "Enhanced: .cpp file class definition support\n";
std::cout << std::string(60, '-') << "\n\n";
// Create processor
SystemCDLLModifier modifier(dryRun, createBackup);
try {
if (modifier.processDirectory(sourceDir)) {
Statistics stats = modifier.getStatistics();
std::string backupDir = modifier.getBackupDir();
printStatistics(stats, dryRun, backupDir);
std::cout << "\nNEXT STEPS:\n";
std::cout << "1. Review modified files for any issues\n";
std::cout << "2. Create a new DLL project in Visual Studio 2015\n";
std::cout << "3. Add SYSTEMC_DLL_EXPORT to preprocessor definitions\n";
std::cout << "4. Add all SystemC source files to the project\n";
std::cout << "5. Build the systemc.dll\n";
std::cout << "6. Test with your SystemC applications\n";
if (!dryRun && backupDir.empty() && createBackup) {
std::cout << "\nWARNING: Backup was not created!\n";
std::cout << "Consider creating a manual backup before proceeding.\n";
}
std::cout << "\nProcessing completed " << (dryRun ? "in dry run mode" : "successfully") << "!\n";
}
else {
std::cout << "\nERROR: Processing failed!\n";
std::cout << "Possible reasons:\n";
std::cout << "1. Invalid SystemC directory\n";
std::cout << "2. Permission issues\n";
std::cout << "3. Disk space problems\n";
std::cout << "4. File system errors\n";
return 1;
}
}
catch (const std::exception& e) {
std::cerr << "\nFATAL ERROR: " << e.what() << "\n";
std::cerr << "Please check:\n";
std::cerr << "1. Directory permissions\n";
std::cerr << "2. Disk space\n";
std::cerr << "3. File system integrity\n";
return 1;
}
return 0;
}
最新发布