Fix to escape VERILATOR_ROOT file paths (#3764) (#3765)

This commit is contained in:
Jiacheng Qian 2022-11-20 23:25:41 +08:00 committed by GitHub
parent 278d532368
commit 47253450a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 30 deletions

View File

@ -54,6 +54,7 @@ Jamie Iles
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
Jiacheng Qian
Jiuyang Liu
John Coiner
John Demme

View File

@ -71,15 +71,6 @@ class CMakeEmitter final {
cmake_set_raw(of, name, raw_value, cache_type, docstring);
}
// Swap all backslashes for forward slashes, because of Windows
static string deslash(const string& s) {
std::string res = s;
for (char& c : res) {
if (c == '\\') c = '/';
}
return res;
}
static void emitOverallCMake() {
const std::unique_ptr<std::ofstream> of{
V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake")};
@ -95,9 +86,9 @@ class CMakeEmitter final {
*of << "# which becomes available after executing `find_package(verilator).\n";
*of << "\n### Constants...\n";
cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), "FILEPATH",
cmake_set(*of, "PERL", V3Options::getenvPERL(), "FILEPATH",
"Perl executable (from $PERL)");
cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), "PATH",
cmake_set(*of, "VERILATOR_ROOT", V3Options::getenvVERILATOR_ROOT(), "PATH",
"Path to Verilator kit (from $VERILATOR_ROOT)");
*of << "\n### Compiler flags...\n";
@ -186,22 +177,22 @@ class CMakeEmitter final {
}
*of << "# Global classes, need linked once per executable\n";
cmake_set_raw(*of, name + "_GLOBAL", deslash(cmake_list(global)));
cmake_set_raw(*of, name + "_GLOBAL", cmake_list(global));
*of << "# Generated module classes, non-fast-path, compile with low/medium optimization\n";
cmake_set_raw(*of, name + "_CLASSES_SLOW", deslash(cmake_list(classes_slow)));
cmake_set_raw(*of, name + "_CLASSES_SLOW", cmake_list(classes_slow));
*of << "# Generated module classes, fast-path, compile with highest optimization\n";
cmake_set_raw(*of, name + "_CLASSES_FAST", deslash(cmake_list(classes_fast)));
cmake_set_raw(*of, name + "_CLASSES_FAST", cmake_list(classes_fast));
*of << "# Generated support classes, non-fast-path, compile with "
"low/medium optimization\n";
cmake_set_raw(*of, name + "_SUPPORT_SLOW", deslash(cmake_list(support_slow)));
cmake_set_raw(*of, name + "_SUPPORT_SLOW", cmake_list(support_slow));
*of << "# Generated support classes, fast-path, compile with highest optimization\n";
cmake_set_raw(*of, name + "_SUPPORT_FAST", deslash(cmake_list(support_fast)));
cmake_set_raw(*of, name + "_SUPPORT_FAST", cmake_list(support_fast));
*of << "# All dependencies\n";
cmake_set_raw(*of, name + "_DEPS", deslash(cmake_list(V3File::getAllDeps())));
cmake_set_raw(*of, name + "_DEPS", cmake_list(V3File::getAllDeps()));
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
cmake_set_raw(*of, name + "_USER_CLASSES", cmake_list(v3Global.opt.cppFiles()));
if (const V3HierBlockPlan* const planp = v3Global.hierPlanp()) {
*of << "# Verilate hierarchical blocks\n";
// Sorted hierarchical blocks in order of leaf-first.
@ -221,10 +212,10 @@ class CMakeEmitter final {
}
*of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE "
<< hblockp->modp()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES ";
<< v3Global.opt.makeDir() + "/" + prefix << " SOURCES ";
for (const auto& childr : children) {
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + childr->hierWrapper(true));
<< v3Global.opt.makeDir() + "/" + childr->hierWrapper(true);
}
*of << " ";
const string vFile = hblockp->vFileIfNecessary();
@ -232,7 +223,7 @@ class CMakeEmitter final {
const V3StringList& vFiles = v3Global.opt.vFiles();
for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " ";
*of << " VERILATOR_ARGS ";
*of << "-f " << deslash(hblockp->commandArgsFileName(true))
*of << "-f " << hblockp->commandArgsFileName(true)
<< " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked
// with .so
<< ")\n";
@ -240,14 +231,14 @@ class CMakeEmitter final {
*of << "\n# Verilate the top module that refers to lib-create wrappers of above\n";
*of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE "
<< v3Global.rootp()->topModulep()->name() << " DIRECTORY "
<< deslash(v3Global.opt.makeDir()) << " SOURCES ";
<< v3Global.opt.makeDir() << " SOURCES ";
for (const auto& itr : *planp) {
*of << " "
<< deslash(v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true));
<< v3Global.opt.makeDir() + "/" + itr.second->hierWrapper(true);
}
*of << " " << deslash(cmake_list(v3Global.opt.vFiles()));
*of << " " << cmake_list(v3Global.opt.vFiles());
*of << " VERILATOR_ARGS ";
*of << "-f " << deslash(planp->topCommandArgsFileName(true));
*of << "-f " << planp->topCommandArgsFileName(true);
*of << ")\n";
}
}

View File

@ -76,6 +76,7 @@ VL_DEFINE_DEBUG_FUNCTIONS;
// Environment
string V3Os::getenvStr(const string& envvar, const string& defaultValue) {
string ret = "";
#if defined(_MSC_VER)
// Note: MinGW does not offer _dupenv_s
const char* envvalue = nullptr;
@ -83,17 +84,18 @@ string V3Os::getenvStr(const string& envvar, const string& defaultValue) {
if (envvalue != nullptr) {
const std::string result{envvalue};
free(envvalue);
return result;
ret = result;
} else {
return defaultValue;
ret = defaultValue;
}
#else
if (const char* const envvalue = getenv(envvar.c_str())) {
return envvalue;
ret = envvalue;
} else {
return defaultValue;
ret = defaultValue;
}
#endif
return VString::escapeStringForPath(ret);
}
void V3Os::setenvStr(const string& envvar, const string& value, const string& why) {

View File

@ -116,6 +116,19 @@ string VString::quoteStringLiteralForShell(const string& str) {
return result;
}
string VString::escapeStringForPath(const string &str) {
if (str.find(R"(\\)") != string::npos) return str; // if it has been escaped already, don't do it again
if (str.find('/') != string::npos) return str; // can be replaced by `__MINGW32__` or `_WIN32`
string result;
const char space = ' '; // escape space like this `Program Files`
const char escape = '\\';
for (const char c: str) {
if (c == space || c == escape) result.push_back(escape);
result.push_back(c);
}
return result;
}
string VString::spaceUnprintable(const string& str) {
string out;
for (const char c : str) {

View File

@ -100,6 +100,9 @@ public:
static string quotePercent(const string& str) { return quoteAny(str, '%', '%'); }
// Surround a raw string by double quote and escape if necessary
// e.g. input abc's becomes "\"abc\'s\""
static string escapeStringForPath(const string& str);
// Escape path in Windows
// e.g. input `C:\Program Files\My Program\My Program.exe` becomes `C:\\Program\ Files\\My\ Program\\My\ Program.exe`
static string quoteStringLiteralForShell(const string& str);
// Replace any unprintable with space
// This includes removing tabs, so column tracking is correct

View File

@ -737,7 +737,7 @@ int main(int argc, char** argv, char** /*env*/) {
V3PreShell::boot();
// Command option parsing
v3Global.opt.buildDepBin(argv[0]);
v3Global.opt.buildDepBin(VString::escapeStringForPath(argv[0]));
const string argString = V3Options::argString(argc - 1, argv + 1);
v3Global.opt.parseOpts(new FileLine{FileLine::commandLineFilename()}, argc - 1, argv + 1);