-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #383 from UebelAndre/verilator
Delete non-deterministic outputs from VerilatorCompile actions
- Loading branch information
Showing
6 changed files
with
269 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,13 @@ | ||
load("@rules_python//python:defs.bzl", "py_binary") | ||
load("@rules_cc//cc:defs.bzl", "cc_binary") | ||
|
||
py_binary( | ||
cc_binary( | ||
name = "verilator_copy_tree", | ||
srcs = ["verilator_copy_tree.py"], | ||
srcs = ["verilator_copy_tree.cc"], | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
cc_binary( | ||
name = "verilator_process_wrapper", | ||
srcs = ["verilator_process_wrapper.cc"], | ||
visibility = ["//visibility:public"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/** | ||
* @file verilator_copy_tree.cc | ||
* @brief A tool for copying generated verilator outputs into unique source and header directories. | ||
*/ | ||
|
||
#include <sys/stat.h> | ||
|
||
#include <cstdlib> | ||
#include <cstring> | ||
#include <fstream> | ||
#include <iostream> | ||
#include <string> | ||
#include <vector> | ||
|
||
#ifdef _WIN32 | ||
#include <direct.h> | ||
#define mkdir(dir, mode) _mkdir(dir) | ||
#else | ||
#include <unistd.h> | ||
#endif | ||
|
||
void create_directory(const std::string& path) { | ||
if (mkdir(path.c_str(), 0700) != 0 && errno != EEXIST) { | ||
std::cerr << "Error creating directory: " << path << std::endl; | ||
std::exit(1); | ||
} | ||
} | ||
|
||
void copy_file(const std::string& src, const std::string& dest) { | ||
std::ifstream src_stream(src, std::ios::binary); | ||
std::ofstream dest_stream(dest, std::ios::binary); | ||
if (!src_stream || !dest_stream) { | ||
std::cerr << "Error copying " << src << " to " << dest << std::endl; | ||
return; | ||
} | ||
dest_stream << src_stream.rdbuf(); | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
if (argc < 5) { | ||
std::cerr << "Usage: " << argv[0] | ||
<< " --src_output=<src_dir> --hdr_output=<hdr_dir> --src=" | ||
"<file1> ... --hdr=<file2> ..." | ||
<< std::endl; | ||
return 1; | ||
} | ||
|
||
std::string src_output = {}; | ||
std::string hdr_output = {}; | ||
std::vector<std::string> srcs = {}; | ||
std::vector<std::string> hdrs = {}; | ||
|
||
for (int i = 1; i < argc; ++i) { | ||
std::string arg = argv[i]; | ||
size_t pos = arg.find('='); | ||
if (pos != std::string::npos) { | ||
std::string key = arg.substr(0, pos); | ||
std::string value = arg.substr(pos + 1); | ||
if (key == "--src_output") { | ||
src_output = value; | ||
} else if (key == "--hdr_output") { | ||
hdr_output = value; | ||
} else if (key == "--src") { | ||
srcs.push_back(value); | ||
} else if (key == "--hdr") { | ||
hdrs.push_back(value); | ||
} else { | ||
std::cerr << "Unexpected argument: " << arg << std::endl; | ||
return 1; | ||
} | ||
} else { | ||
std::cerr << "Unexpected argument: " << arg << std::endl; | ||
return 1; | ||
} | ||
} | ||
|
||
if (src_output.empty() || hdr_output.empty()) { | ||
std::cerr << "Both --src_output and --hdr_output must be specified." | ||
<< std::endl; | ||
return 1; | ||
} | ||
|
||
create_directory(src_output); | ||
create_directory(hdr_output); | ||
|
||
for (const std::string& file : srcs) { | ||
copy_file(file, | ||
src_output + "/" + file.substr(file.find_last_of("/\\") + 1)); | ||
} | ||
|
||
for (const std::string& file : hdrs) { | ||
copy_file(file, | ||
hdr_output + "/" + file.substr(file.find_last_of("/\\") + 1)); | ||
} | ||
|
||
return 0; | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/** | ||
* @file verilator_process_wrapper.cc | ||
* @brief A process wrapper for the `VerilatorCompile` Bazel action. | ||
*/ | ||
|
||
#include <cstdlib> | ||
#include <iostream> | ||
#include <string> | ||
#include <vector> | ||
|
||
#ifdef _WIN32 | ||
#include <windows.h> | ||
#else | ||
#include <dirent.h> | ||
#include <unistd.h> | ||
#endif | ||
|
||
/** | ||
* @brief Checks if a filename ends with any of the given suffixes. | ||
* | ||
* @param filename The name of the file. | ||
* @param suffixes A vector of suffixes to match. | ||
* @return true if the filename ends with any suffix, false otherwise. | ||
*/ | ||
bool ends_with_any(const std::string& filename, | ||
const std::vector<std::string>& suffixes) { | ||
for (const auto& suffix : suffixes) { | ||
if (filename.size() >= suffix.size() && | ||
filename.compare(filename.size() - suffix.size(), suffix.size(), | ||
suffix) == 0) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* @brief Deletes files in the specified directory that match given suffixes. | ||
* | ||
* @param dir The directory to scan for matching files. | ||
* @param suffixes The list of suffixes to check for deletion. | ||
* * @return A non-zero exit code if any issues occurred. | ||
*/ | ||
int delete_matching_files(const std::string& dir, | ||
const std::vector<std::string>& suffixes) { | ||
if (dir.empty()) return 0; | ||
|
||
#ifdef _WIN32 | ||
std::string search_path = dir + "\\*"; | ||
WIN32_FIND_DATAA find_data = {}; | ||
HANDLE h_find = FindFirstFileA(search_path.c_str(), &find_data); | ||
|
||
if (h_find != INVALID_HANDLE_VALUE) { | ||
do { | ||
std::string filename = find_data.cFileName; | ||
if (ends_with_any(filename, suffixes)) { | ||
std::string file_path = dir + "\\" + filename; | ||
if (!DeleteFileA(file_path.c_str())) { | ||
std::cerr << "Error: Failed to delete: " << file_path | ||
<< std::endl; | ||
return 1; | ||
} | ||
} | ||
} while (FindNextFileA(h_find, &find_data) != 0); | ||
FindClose(h_find); | ||
} | ||
#else | ||
DIR* dir_stream = opendir(dir.c_str()); | ||
if (!dir_stream) { | ||
std::cerr << "Error accessing directory: " << dir << std::endl; | ||
return 1; | ||
} | ||
|
||
struct dirent* entry = nullptr; | ||
while ((entry = readdir(dir_stream)) != nullptr) { | ||
std::string filename = entry->d_name; | ||
if (ends_with_any(filename, suffixes)) { | ||
std::string file_path = dir + "/" + filename; | ||
int result = remove(file_path.c_str()); | ||
if (result != 0) { | ||
std::cerr << "Error: Failed to delete: " << file_path | ||
<< std::endl; | ||
return result; | ||
} | ||
} | ||
} | ||
closedir(dir_stream); | ||
#endif | ||
return 0; | ||
} | ||
|
||
int main(int argc, char* argv[]) { | ||
std::string output_dir{}; | ||
std::vector<std::string> command{}; | ||
|
||
// Parse arguments | ||
for (int i = 1; i < argc; ++i) { | ||
std::string arg = argv[i]; | ||
|
||
command.push_back(arg); | ||
|
||
// Store the output directory value | ||
if (arg == "--Mdir" && i + 1 < argc) { | ||
output_dir = argv[i + 1]; | ||
} | ||
} | ||
|
||
if (command.empty()) { | ||
std::cerr << "Error: No command provided to execute." << std::endl; | ||
return 1; | ||
} | ||
|
||
// Execute verilator command. | ||
std::string cmd = {}; | ||
for (const std::string& part : command) { | ||
cmd += part + " "; | ||
} | ||
int result = std::system(cmd.c_str()); | ||
if (result != 0) { | ||
return result; | ||
} | ||
|
||
// Delete any non-deterministic files. | ||
if (std::getenv("VERILATOR_AVOID_NONDETERMINISTIC_OUTPUTS") != nullptr) { | ||
std::vector<std::string> suffixes = {"__verFiles.dat"}; | ||
if (delete_matching_files(output_dir, suffixes)) { | ||
return 1; | ||
} | ||
} | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
# A build flag for deleting files known to be non-deterministic from `VerilatorCompile` | ||
# actions such as the `__verFiles.dat` file which contains timing data for each generated | ||
# file. | ||
bool_flag( | ||
name = "avoid_nondeterministic_outputs", | ||
build_setting_default = False, | ||
) |