diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 20655cd4e66b47c98553f2a4296732dba7fa3bbd..cc1eb71dfcb18268f0636d4b99a2749f813ffc8c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -53,8 +53,8 @@ test-das6: script: - cmake -S . -B build ${CMAKE_OPTIONS} -DPMT_BUILD_NVML=ON -DPMT_BUILD_BINARY=ON - make -C build - - PMT_NAME=rapl $(pwd)/build/bin/PMT sleep 3 - - PMT_NAME=nvml $(pwd)/build/bin/PMT sleep 3 + - $(pwd)/build/bin/PMT --name rapl -- sleep 3 + - $(pwd)/build/bin/PMT --name nvml -- sleep 3 - PYTHONPATH=$PYTHONPATH:$(pwd)/build/python/site-packages python3 ${CI_PROJECT_DIR}/python/demo.py test-das6-integration: diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 233b8b9ef791fd033b76a37c5e57cf9283eb4ab8..a9d871018464475d70490f9e6ccb4aed1267eb59 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -1,8 +1,14 @@ project(PMT) +FetchContent_Declare( + cxxopts + GIT_REPOSITORY https://github.com/jarro2783/cxxopts.git + GIT_TAG v3.2.1) +FetchContent_MakeAvailable(cxxopts) + add_executable(${PROJECT_NAME} main.cpp) -target_link_libraries(${PROJECT_NAME} pmt) +target_link_libraries(${PROJECT_NAME} cxxopts pmt) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}) diff --git a/bin/main.cpp b/bin/main.cpp index 8bae3505599ab89fa92ffeff181c94154156f713..1c293fb502669c227a230561e67ebe7040eb2fa9 100644 --- a/bin/main.cpp +++ b/bin/main.cpp @@ -5,13 +5,51 @@ #include <stdexcept> #include <string> +#include <cxxopts.hpp> + #include <pmt.h> -void run(pmt::PMT& sensor, int argc, char* argv[]) { +cxxopts::Options create_commandline_parser(char* argv[]) { + cxxopts::Options options(argv[0]); + + options.add_options()("n,name", "Name (required)", + cxxopts::value<std::string>())( + "d,device", "Device (optional)", + cxxopts::value<std::string>()->default_value("default_device"))( + "command", "Command (optional)", + cxxopts::value<std::vector<std::string>>()->default_value({}))( + "h,help", "Print usage"); + options.parse_positional({"command"}); + + return options; +} + +cxxopts::ParseResult parse_commandline(cxxopts::Options& options, int argc, + char* argv[]) { + try { + cxxopts::ParseResult result = options.parse(argc, argv); + + if (result.count("help")) { + std::cout << options.help() << std::endl; + exit(EXIT_SUCCESS); + } + + if (!result.count("name")) { + throw cxxopts::exceptions::missing_argument("name"); + } + + return result; + } catch (const cxxopts::exceptions::exception& e) { + std::cerr << options.help() << std::endl; + exit(EXIT_FAILURE); + } +} + +void run(pmt::PMT& sensor, const std::vector<std::string>& command) { const char* filename = std::getenv(pmt::kDumpFilenameVariable.c_str()); sensor.StartDump(filename); - if (argc == 1) { + if (command.empty()) { auto first = sensor.Read(); while (true) { auto state = sensor.Read(); @@ -27,16 +65,17 @@ void run(pmt::PMT& sensor, int argc, char* argv[]) { std::chrono::milliseconds(sensor.GetMeasurementInterval())); } } else { - std::stringstream command; - for (int i = 1; i < argc; i++) { + std::stringstream command_stream; + for (int i = 1; i < command.size(); i++) { if (i > 1) { - command << " "; + command_stream << " "; } - command << argv[i]; + command_stream << command[i]; } + const std::string command_string = command_stream.str(); auto start = sensor.Read(); - if (system(command.str().c_str()) != 0) { - perror(command.str().c_str()); + if (system(command_string.c_str()) != 0) { + perror(command_string.c_str()); } auto end = sensor.Read(); std::cout << "Runtime: " << pmt::PMT::seconds(start, end) << " s" @@ -48,18 +87,17 @@ void run(pmt::PMT& sensor, int argc, char* argv[]) { } int main(int argc, char* argv[]) { + cxxopts::Options options = create_commandline_parser(argv); + const cxxopts::ParseResult result = parse_commandline(options, argc, argv); + const std::string pmt_name = result["name"].as<std::string>(); + const std::string pmt_device = result["device"].as<std::string>(); + const std::vector<std::string> command = + result["command"].as<std::vector<std::string>>(); + try { - const std::string pmt_name_env = "PMT_NAME"; - const std::string pmt_device_env = "PMT_DEVICE"; - const char* pmt_name = std::getenv(pmt_name_env.c_str()); - const char* pmt_device = std::getenv(pmt_device_env.c_str()); - if (pmt_name == nullptr) { - throw std::runtime_error( - "Select PMT using the PMT_NAME environment variable."); - } else { - std::unique_ptr<pmt::PMT> sensor = pmt::Create(pmt_name, pmt_device); - run(*sensor, argc, argv); - } + std::unique_ptr<pmt::PMT> sensor = + pmt::Create(pmt_name.c_str(), pmt_device.c_str()); + run(*sensor, command); return EXIT_SUCCESS; } catch (const std::exception& e) { std::cerr << "Error: " << e.what();