diff --git a/README.build.txt b/README.build.txt index 9befebd..7b53864 100644 --- a/README.build.txt +++ b/README.build.txt @@ -1,84 +1,107 @@ =========================== Building the RoSA Framework =========================== General notes: ------------- The provided CMake project supports only out-of-tree builds, i.e. one needs to create a build directory and run CMake in that using the source directory path as argument. CMake Variables: --------------- Beyond the usual CMake variables, the following project-related options are available: * ROSA_INCLUDE_TOOLS, defaults to ON * ROSA_INCLUDE_EXAMPLES, defaults to ON * ROSA_ENABLE_PEDANTIC, defaults to ON * ROSA_ENABLE_ASSERTIONS, defaults to ON only for debug builds, and its value is respected only for non-debug builds * ROSA_LOG_LEVEL, defaults to none, use a valid integer value to enable logging ** 0 - ERROR ** 1 - WARNING ** 2 - INFO ** 3 - DEBUG ** 4 - TRACE -Set C and C++ compilers with the variables CC and CXX, respectively. Use the -CMake variable CMAKE_BUILD_TYPE for single-configuration generators to set the -type of build: Debug, Release. - Build on Linux with Make: ------------------------ Building the framework on Linux using Make is a straightforward process which does not require performing any tricks. The framework compiles with Clang 3.8.0. -Follows an example how to build the framework once having the sources fetched -into a directory called rosa and Clang executables available via your PATH. +Set C and C++ compilers with the variables CC and CXX, respectively. Use the +CMake variable CMAKE_BUILD_TYPE to set the type of build: Debug, Release. + +Follows an example on building the framework. You need to have RoSA sources on +your computer and Clang executables available via your PATH. -rosa$ cd .. -$ mkdir build.rosa -$ cd build.rosa -build.rosa$ CC=clang CXX=clang++ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DROSA_LOG_LEVEL="4" ../rosa/ +rosa-src$ cd .. +$ mkdir rosa-build +$ cd rosa-build +rosa-build$ CC=clang CXX=clang++ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DROSA_LOG_LEVEL="4" ../rosa-src/ [CMake configures and generates without errors] $ make [Make builds the project] +You just need to re-run Make in order to re-build the project after changing +the source code and the CMake project. In case the CMake project is changed, +Make automatically calls CMake to update the build project accordingly. + Build on Windows with Visual Studio: ----------------------------------- Unfortunately, the native MSVC compiler cannot compile the framework. One needs to use Clang with Visual Studio in order to build the framework. There are two alternatives to this: * using the Clang/C2 module for Visual Studio 2017, * installing LLVM for Windows and using it as an external toolset for Visual Studio (necessary for older versions of Visual Studio). For using Visual Studio 2017, which would be the preferred way, one needs to select "Clang/C2 (experimental)" on the "Individual components" tab in Visual Studio Installer. For using LLVM for Windows, one downloads the official binary release from http://llvm.org and consults with its documentation. The release provides integration for Visual Studio versions between 2010 and 2014 (as of LLVM 4.0.0). Having your build system prepared and RoSA sources fetched to your computer, build the framework like this: * Generate Visual Studio solution with CMake ** Define the source directory and a separate build directory in CMake ** Click Configure ** Select the proper generator for your version of Visual Studio ** Define your optional toolset (argument for -T) *** Clang/C2 with VS2017: v141_clang_c2 *** LLVM for Windows with older VS: LLVM-vs ** Click Finish ** Tune CMake variables as you will +*** Note that Visual Studio Generators are multi-configuration generators, hence + you cannot set CMAKE_BUILD_TYPE. You need to select a configuration to build + in Visual Studio. ** Click Generate +* Fix the generated Visual Studio projects (applies for Clang/C2) +** The ExceptionHandling option in the generated projects is 'Sync', which is an + invalid value for Clang/C2 and needs to be changed to 'Enabled' in all + Visual Studio project files +*** with GNU tools +rosa-build$ find . -name "*.vcxproj" -print|xargs sed -i -e 's/Sync/Enabled/g' +*** with PowerShell +rosa-build> ls *.vcxproj -rec | %{ $f=$_; (gc $f.PSPath) | %{ $_ -replace "Sync", "Enabled" } | sc $f.PSPath } +** Note that the project files need to be fixed every time CMake regenerates + them, which may happen when building the project in Visual Studio in case + you have the CMake project changed in the source directory. * Build the framework with Visual Studio ** Open the generated RoSA.sln from the build directory with Visual Studio ** Build the project ALL_BUILD +You just need to re-build the project in Visual Studio after changing the +source code and the CMake project. In case the CMake project is changed, Visual +Studio automatically calls CMake the update the build project accordingly. Do +not forget to fix the newly generated Visual Studio project files if you use +Clang/C2 with Visual Studio 2017. + diff --git a/cmake/modules/HandleROSAOptions.cmake b/cmake/modules/HandleROSAOptions.cmake index d71e140..b53733a 100644 --- a/cmake/modules/HandleROSAOptions.cmake +++ b/cmake/modules/HandleROSAOptions.cmake @@ -1,78 +1,86 @@ # This CMake module is responsible for interpreting the user defined ROSA_ # options and executing the appropriate CMake commands to realize the users' # selections. include(CheckCCompilerFlag) include(CheckCXXCompilerFlag) if( CMAKE_COMPILER_IS_GNUCXX ) set(ROSA_COMPILER_IS_GCC_COMPATIBLE ON) -elseif( MSVC ) - set(ROSA_COMPILER_IS_GCC_COMPATIBLE OFF) elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) set(ROSA_COMPILER_IS_GCC_COMPATIBLE ON) +elseif( MSVC ) + set(ROSA_COMPILER_IS_GCC_COMPATIBLE OFF) endif() function(append value) foreach(variable ${ARGN}) set(${variable} "${${variable}} ${value}" PARENT_SCOPE) endforeach(variable) endfunction() function(append_if condition value) if (${condition}) foreach(variable ${ARGN}) set(${variable} "${${variable}} ${value}" PARENT_SCOPE) endforeach(variable) endif() endfunction() # NDEBUG on non-Debug builds append("-DNDEBUG" CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL) # Assertions are always enabled on Debug builds, this is interesting for # non-Debug builds. if( ROSA_ENABLE_ASSERTIONS ) # MSVC doesn't like _DEBUG on release builds. See PR 4379. if( NOT MSVC ) add_definitions( -D_DEBUG ) set(ENABLE_ASSERTIONS "1") else() set(ENABLE_ASSERTIONS "0") endif() # On non-Debug builds we NDEBUG, but in this case we need to undefine it: add_definitions(-UNDEBUG) # Also remove /D NDEBUG to avoid MSVC warnings about conflicting defines. foreach (flags_var_to_scrub CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS_MINSIZEREL) string (REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " "${flags_var_to_scrub}" "${${flags_var_to_scrub}}") endforeach() endif( ROSA_ENABLE_ASSERTIONS ) #FIXME: Disable RTTI and exceptions, once gen_agent_test2 is cleared up. if( ROSA_COMPILER_IS_GCC_COMPATIBLE ) append("-Wall -Wextra -Werror" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) append_if(ROSA_ENABLE_PEDANTIC "-pedantic -Wno-long-long" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) - check_cxx_compiler_flag("-std=c++11" CXX_SUPPORTS_CXX11) - if (CXX_SUPPORTS_CXX11) - append("-std=c++11" CMAKE_CXX_FLAGS) + check_cxx_compiler_flag("-std=c++14" CXX_SUPPORTS_CXX14) + if ( CXX_SUPPORTS_CXX14 ) + append("-std=c++14" CMAKE_CXX_FLAGS) else() - message(FATAL_ERROR "RoSA requires C++11 support but the '-std=c++11' flag isn't supported.") + message(FATAL_ERROR "RoSA requires C++14 support but the '-std=c++14' flag isn't supported.") endif() + + check_c_compiler_flag("-std=c11" C_SUPPORTS_C11) + if ( C_SUPPORTS_C11 ) + append("-std=c11" CMAKE_C_FLAGS) + else() + message(FATAL_ERROR "RoSA requires C11 support but the '-std=c11' flag isn't supported.") + endif() + else ( ROSA_COMPILER_IS_GCC_COMPATIBLE ) # FIXME: set the same things as for GCC-compatible compilers endif( ROSA_COMPILER_IS_GCC_COMPATIBLE ) diff --git a/lib/gen_agent_test2/CSVreaderModule.cpp b/lib/gen_agent_test2/CSVreaderModule.cpp index c331131..90fcd24 100644 --- a/lib/gen_agent_test2/CSVreaderModule.cpp +++ b/lib/gen_agent_test2/CSVreaderModule.cpp @@ -1,156 +1,171 @@ #include "CSVreaderModule.h" +#include "rosa/config/config.h" #include #include #include #define STRINGLENGTH 5000 void CSVreaderModule::initialize_csvreader(FILE *fpointer, unsigned int column, unsigned int start_row) { // fpointer_read = fopen(filepath_read, "r"); // TODO: file ponter schon aus CSV-Reader Creator Funktion übergeben.. dann // kann man nämlich ausgeben, wenn da was nicht erstellt werden kann // bool file_opened = fopen_s(&fpointer_read, filepath_read, "r"); // TODO: etwas mit flag this->fpointer = fpointer; this->row = 1; this->column = column; this->start_row = start_row; flag_csv_reader_configured = true; } CSVreaderModule::CSVreaderModule() { set_name(NO_NAME); flag_csv_reader_configured = false; } CSVreaderModule::CSVreaderModule(const char *name) { set_name(name); flag_csv_reader_configured = false; } CSVreaderModule::CSVreaderModule(FILE *fpointer, unsigned int column, unsigned int start_row) { set_name(NO_NAME); if (fpointer) { initialize_csvreader(fpointer, column, start_row); } else { flag_csv_reader_configured = false; } } CSVreaderModule::CSVreaderModule(const char *name, FILE *fpointer, unsigned int column, unsigned int start_row) { set_name(name); if (fpointer) { initialize_csvreader(fpointer, column, start_row); } else { flag_csv_reader_configured = false; } } /* CSV_Reader :: CSV_Reader(char* name, char* filepath_read, int column, int start_row) { } */ // XXX: Wird nicht mehr benutzt // TODO: überarbeiten nach folgendem Beispiel // https://msdn.microsoft.com/en-us/library/ftsafwz3.aspx bool CSVreaderModule::read_one_row() { if (fpointer) { char readrow[STRINGLENGTH] = "" /*, electedfield[STRINGLENGTH] = ""*/; // TODO: move following for-loop to "initialize_csvreader(...) for (; row < start_row; row++) { if (!fgets(readrow, STRINGLENGTH, fpointer)) return false; } if (fgets(readrow, STRINGLENGTH, fpointer)) { - char *ptr; + auto strtok_f = +#ifdef ROSA_WINDOWS + strtok_s +#else + strtok_r +#endif + ; + char *ptr, *tokptr; // TODO: make delimiter configurable! - ptr = strtok(readrow, ",;"); + ptr = strtok_f(readrow, ",;", &tokptr); // OLD: unsigned int dataset_counter = 0; dataset_counter = 0; if (list_of_datasets[dataset_counter] == 1) { data_read[dataset_counter] = std::stof(ptr, NULL); dataset_counter++; } else { - ptr = strtok(NULL, ",;"); + ptr = strtok_f(NULL, ",;", &tokptr); } for (; dataset_counter < num_of_datasets; dataset_counter++) { for (unsigned int c_ix = list_of_datasets[dataset_counter - 1]; c_ix < list_of_datasets[dataset_counter]; c_ix++) { - ptr = strtok(NULL, ",;"); + ptr = strtok_f(NULL, ",;", &tokptr); } data_read[dataset_counter] = std::stof(ptr, NULL); } return true; } } return false; } float CSVreaderModule::get_value_of_field(unsigned int field) { // TODO: Bessere Fehlerbehandlung.. also nciht einfach 0 returnen, wenn kein // richtiges FEld!!! if (field < num_of_datasets) { return data_read[field]; } return 0.0; } // TODO: überarbeiten nach folgendem Beispiel // https://msdn.microsoft.com/en-us/library/ftsafwz3.aspx bool CSVreaderModule::read_field() { if (fpointer) { char readrow[STRINGLENGTH] = "" /*, electedfield[STRINGLENGTH] = ""*/; // TODO: move following for-loop to "initialize_csvreader(...) for (; row < start_row; row++) { if (!fgets(readrow, STRINGLENGTH, fpointer)) return false; } if (fgets(readrow, STRINGLENGTH, fpointer)) { - char *ptr; + auto strtok_f = +#ifdef ROSA_WINDOWS + strtok_s +#else + strtok_r +#endif + ; + char *ptr, *tokptr; // TODO: make delimiter configurable! - ptr = strtok(readrow, ",;"); + ptr = strtok_f(readrow, ",;", &tokptr); for (unsigned int d_ix = 1; d_ix < column; d_ix++) { - ptr = strtok(NULL, ",;"); + ptr = strtok_f(NULL, ",;", &tokptr); } input_data = std::stof(ptr, NULL); return true; } } return false; } bool CSVreaderModule::get_next_value(float *value) { if (flag_csv_reader_configured) { if (read_field()) { *value = input_data; return true; } } return false; } // TODO: flag_csv_reader_configured abfragen void CSVreaderModule::close_file() { fclose(fpointer); } diff --git a/lib/gen_agent_test2/Module.cpp b/lib/gen_agent_test2/Module.cpp index 7ada945..2da1f43 100644 --- a/lib/gen_agent_test2/Module.cpp +++ b/lib/gen_agent_test2/Module.cpp @@ -1,12 +1,17 @@ #include "Module.h" +#include "rosa/config/config.h" #include Module::Module() { set_name(NO_NAME); } Module::Module(const char *name) { set_name(name); } void Module::set_name(const char *name) { +#ifdef ROSA_WINDOWS + strncpy_s(this->name, MAX_LENGTH_NAME, name, MAX_LENGTH_NAME); +#else strncpy(this->name, name, MAX_LENGTH_NAME); +#endif } const char *Module::get_name() { return this->name; } diff --git a/lib/gen_agent_test2/create_unit.cpp b/lib/gen_agent_test2/create_unit.cpp index a0632f2..3bc5e67 100644 --- a/lib/gen_agent_test2/create_unit.cpp +++ b/lib/gen_agent_test2/create_unit.cpp @@ -1,229 +1,238 @@ #include "create_unit.h" +#include "rosa/config/config.h" #include //#include "rlutil.h" // using namespace rlutil; Agent create_agent() { return create_agent(NO_NAME); } Agent create_agent(const char *name) { Agent agent(name); printf(" > Agent "); // setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", agent.get_name()); // setColor(TXTCOLOR_GREY); printf("(id: %03u) ", agent.get_id()); // setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // setColor(TXTCOLOR_GREY); return agent; } Sensor create_sensor() { return create_sensor(NO_NAME); } Sensor create_sensor(const char *name) { Sensor sensor(name); printf(" > Sensor "); // setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", sensor.get_name()); // setColor(TXTCOLOR_GREY); printf("(id: %03u) ", sensor.get_id()); // setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // setColor(TXTCOLOR_GREY); return sensor; } HistoryModule create_historyModule(unsigned int history_length, int delimitation_mode) { return create_historyModule(NO_NAME, history_length, delimitation_mode); } HistoryModule create_historyModule(const char *name, unsigned int history_length, int delimitation_mode) { HistoryModule historyModule(name); printf(" > History "); // setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", historyModule.get_name()); // setColor(TXTCOLOR_GREY); printf("(id: %03u) ", historyModule.get_id()); // setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // setColor(TXTCOLOR_GREY); if (historyModule.set_maxHistoryLength(history_length)) { printf(" > History length "); // setColor(TXTCOLOR_LIGHTGREEN); printf("set "); // setColor(TXTCOLOR_GREY); printf("to %u\n", history_length); } else { // setColor(TXTCOLOR_LIGHTRED); printf(" > historyLength could not set (out of allowed range)."); // setColor(TXTCOLOR_GREY); } if (historyModule.set_delimitationMode(delimitation_mode)) { printf(" > Delimitation Mode "); // setColor(TXTCOLOR_LIGHTGREEN); printf("set "); // setColor(TXTCOLOR_GREY); printf("to %u\n", delimitation_mode); } else { // setColor(TXTCOLOR_LIGHTRED); printf(" > Delimitation Mode could not set (out of allowed range)."); // setColor(TXTCOLOR_GREY); } return historyModule; } Channel create_channel(unsigned int transfer_rate) { return create_channel(NO_NAME, transfer_rate); } Channel create_channel(const char *name, unsigned int transfer_rate) { Channel channel(name); printf(" > Channel "); // setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", channel.get_name()); // setColor(TXTCOLOR_GREY); printf("(id: %03u) ", channel.get_id()); // setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // setColor(TXTCOLOR_GREY); if (channel.set_transferRate(transfer_rate)) { if (transfer_rate != 0) { printf(" > transfer rate "); // setColor(TXTCOLOR_LIGHTGREEN); printf("set "); // setColor(TXTCOLOR_GREY); printf("to %i\n", transfer_rate); } else { printf(" > transfer "); // setColor(TXTCOLOR_LIGHTGREEN); printf("set "); // setColor(TXTCOLOR_GREY); printf("to immediately transportation\n" /*, transfer_rate*/); } } else { // setColor(TXTCOLOR_LIGHTRED); printf(" > Transfer Rate out of allowed bounds!\n"); // setColor(TXTCOLOR_GREY); } return channel; } Testbench create_testbench() { Testbench testbench; printf(" > "); // setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", testbench.get_name()); // rlutil::setColor(TXTCOLOR_GREY); printf("(id: %03u) ", testbench.get_id()); // rlutil::setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // rlutil::setColor(TXTCOLOR_GREY); return testbench; } Testbench create_testbench(const char *name) { Testbench testbench(name); printf(" > "); // rlutil::setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", testbench.get_name()); // rlutil::setColor(TXTCOLOR_GREY); printf("(id: %03u) ", testbench.get_id()); // rlutil::setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // rlutil::setColor(TXTCOLOR_GREY); return testbench; } FILE *make_file_pointer(const char *filepath, int mode) { FILE *fpointer; // bool file_opened; if (mode == CSV_MODE_READ) { +#ifdef ROSA_WINDOWS + fopen_s(&fpointer, filepath, "r"); +#else fpointer = fopen(filepath, "r"); +#endif // file_opened = fopen_s(&fpointer, filepath, "r"); } else if (mode == CSV_MODE_WRITE) { +#ifdef ROSA_WINDOWS + fopen_s(&fpointer, filepath, "r"); +#else fpointer = fopen(filepath, "r"); +#endif // file_opened = fopen_s(&fpointer, filepath, "w"); } else { printf("File pointer mode for \"%s\" ", filepath); // rlutil::setColor(TXTCOLOR_LIGHTRED); printf("is not supported!\n"); // rlutil::setColor(TXTCOLOR_GREY); return NULL; } if (fpointer /*file_opened == 0*/) { return fpointer; } printf("File pointer \"%s\" ", filepath); // rlutil::setColor(TXTCOLOR_LIGHTRED); printf("could not created!\n"); // rlutil::setColor(TXTCOLOR_GREY); return NULL; } void print_csv_reader(CSVreaderModule csvReaderModule, const char *filepath) { printf(" > "); // rlutil::setColor(TXTCOLOR_LIGHTCYAN); printf("%s ", csvReaderModule.get_name()); // rlutil::setColor(TXTCOLOR_GREY); printf("(id: %03u) for \"%s\" ", csvReaderModule.get_id(), filepath); // rlutil::setColor(TXTCOLOR_LIGHTGREEN); printf("created\n"); // rlutil::setColor(TXTCOLOR_GREY); } CSVreaderModule create_CSVreaderModule(const char *filepath, unsigned int column, unsigned int start_row) { FILE *fpointer = make_file_pointer(filepath, CSV_MODE_READ); if (fpointer) { CSVreaderModule csvr(fpointer, column, start_row); print_csv_reader(csvr, filepath); return csvr; } else { CSVreaderModule csvr; return csvr; } } CSVreaderModule create_CSVreaderModule(const char *name, const char *filepath, unsigned int column, unsigned int start_row) { FILE *fpointer = make_file_pointer(filepath, CSV_MODE_READ); if (fpointer) { CSVreaderModule csvr(name, fpointer, column, start_row); print_csv_reader(csvr, filepath); return csvr; } else { CSVreaderModule csvr; return csvr; } } diff --git a/lib/support/terminal_colors.cpp b/lib/support/terminal_colors.cpp index 4f8ca4c..0c35ed2 100644 --- a/lib/support/terminal_colors.cpp +++ b/lib/support/terminal_colors.cpp @@ -1,76 +1,77 @@ /******************************************************************************* * * File: terminal_colors.cpp * * Contents: Facility for printing colorized text to terminals supporting it. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #include "rosa/support/terminal_colors.h" #include "rosa/config/config.h" #include "rosa/support/debug.hpp" #include #ifdef ROSA_POSIX #include #endif // defined(ROSA_POSIX) namespace rosa { namespace terminal { // ANSI color codes for POSIX terminals. // NOTE: Use std::array for runtime efficiency, though static casting is // necessary for indexing. // NOTE: Do not index with Color::NumColors! constexpr std::array(Color::NumColors)> ANSIColorCodes{{ "0", // Default - Attribute reset "30", // Black "31", // Red "32", // Green "33", // Yelow "34", // Blue "35", // Magenta "36", // Cyan "37", // Lightgrey "90", // Darkgrey "91", // Lightred "92", // Lightgreen "93", // Lightyellow "94", // Lightblue "95", // Lightmagenta "96", // Lightcyan "97" // White }}; std::ostream &operator<<(std::ostream &os, const Color color) { ASSERT(color != Color::NumColors); // Handle color only when printing to terminal and it supports colors. #ifdef ROSA_POSIX // Identify terminal by checking if the stream is buffered as one of the // standard outputs, and the corresponding C standard output stream is // pointing to a terminal. // NOTE: This implementation may be tricked so that it does not print color // to terminal, but should never print color codes to a non-terminal output. if ((os.rdbuf() == std::cout.rdbuf() && isatty(fileno(stdin))) || ((os.rdbuf() == std::cerr.rdbuf() || os.rdbuf() == std::clog.rdbuf()) && isatty(fileno(stderr)))) { os << "\033[" << ANSIColorCodes[static_cast(color)] << "m"; } #elif defined(ROSA_WINDOWS) // FIXME: Windows terminals support ANSI color codes from Windows 10 // Threshold 2, custom stuff is required for earlier versions. + (void)ANSIColorCodes; // To shut up compiler warning. #endif // defined(ROSA_POSIX) || defined(ROSA_WINDOWS) return os; } } // End namespace terminal } // End namespace rosa