/******************************************************************************** * Copyright (c) 2025-2026 ZF Friedrichshafen AG * * This program and the accompanying materials are made available under the * terms of the Apache License Version 2.0 which is available at * https://www.apache.org/licenses/LICENSE-2.0 * * SPDX-License-Identifier: Apache-2.0 * * Contributors: * Erik Verhoeven - initial API and implementation ********************************************************************************/ #include "cmake_generator.h" #include #include #include #include #include #include CDbcUtilCMakeGenerator::CDbcUtilCMakeGenerator(const std::filesystem::path& rpathOutputDir, const std::string& rssComponent) { if (rssComponent.empty()) return; // TODO: Exception // Create project directory if (!rpathOutputDir.empty()) m_pathProject = rpathOutputDir; if (!rssComponent.empty()) m_pathProject /= "can_dl"; std::filesystem::create_directories(m_pathProject); // The source string std::string ssSource; // File with "CMakeLists.txt" function; read completely if existing std::filesystem::path pathFile = m_pathProject / "CMakeLists.txt"; if (std::filesystem::exists(pathFile)) { std::ifstream stream; stream.open(pathFile); if (!stream.is_open()) return; // TODO: Exception: throw CCompileException("Failed to open the CMakeLists.txt file for reading."); // Read the complete source std::stringstream sstream; sstream << stream.rdbuf(); ssSource = std::move(sstream.str()); } else // Create the file in memory { ssSource = R"code(# Enforce CMake version 3.20 or newer needed for path function cmake_minimum_required (VERSION 3.20) # Use new policy for project version settings and default warning level cmake_policy(SET CMP0048 NEW) # requires CMake 3.14 cmake_policy(SET CMP0092 NEW) # requires CMake 3.15 # Define project project(%component% VERSION 1.0 LANGUAGES CXX) # Use C++17 support set(CMAKE_CXX_STANDARD 17) # Library symbols are hidden by default set(CMAKE_CXX_VISIBILITY_PRESET hidden) # Set the SDV_FRAMEWORK_DEV_INCLUDE if not defined yet if (NOT DEFINED SDV_FRAMEWORK_DEV_INCLUDE) if (NOT DEFINED ENV{SDV_FRAMEWORK_DEV_INCLUDE}) message( FATAL_ERROR "The environment variable SDV_FRAMEWORK_DEV_INCLUDE needs to be pointing to the SDV V-API development include files location!") endif() set (SDV_FRAMEWORK_DEV_INCLUDE "$ENV{SDV_FRAMEWORK_DEV_INCLUDE}") endif() # Include link to export directory of SDV V-API development include files location include_directories(${SDV_FRAMEWORK_DEV_INCLUDE}) # Set platform specific compile flags if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_compile_options(/W4 /WX /wd4996 /wd4100 /permissive- /Zc:rvalueCast) else() add_compile_options(-Werror -Wall -Wextra -Wshadow -Wpedantic -Wunreachable-code -fno-common) endif() # Add the dynamic library add_library(%component% SHARED) # Set extension to .sdv set_target_properties(%component% PROPERTIES PREFIX "") set_target_properties(%component% PROPERTIES SUFFIX ".sdv") )code"; CKeywordMap mapKeywords; mapKeywords["component"] = rssComponent; ssSource = ReplaceKeywords(ssSource, mapKeywords); } // Search function for caseless finding in the string. auto fnNCFind = [&](const std::string& rssText, size_t nPos = 0) -> size_t { auto it = std::search(ssSource.begin() + nPos, ssSource.end(), rssText.begin(), rssText.end(), [](unsigned char ch1, unsigned char ch2) { return std::tolower(ch1) == std::tolower(ch2); } ); if (it == ssSource.end()) return std::string::npos; return std::distance(ssSource.begin(), it); }; // Find the add_library function size_t nPos = fnNCFind("add_library"); if (nPos == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing 'add_library' keyword."); // Search for shared keyword nPos = fnNCFind("shared", nPos); if (nPos == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing 'shared' keyword."); nPos += 6; // Build set with files size_t nStop = fnNCFind(")", nPos); if (nStop == std::string::npos) return; // TODO: Exception: throw CCompileException("Missing ')' closing the 'add_library' statement."); std::set setFiles; while (nPos < nStop) { // Skip whitespace while (std::isspace(ssSource[nPos])) nPos++; // Read file name size_t nFileBegin = nPos; while (nPos < nStop && !std::isspace(ssSource[nPos])) nPos++; // Store the file setFiles.insert(ssSource.substr(nFileBegin, nPos - nFileBegin)); } // Insert additional files if needed size_t nSourceSize = ssSource.size(); if (setFiles.find("datalink.h") == setFiles.end()) ssSource.insert(nStop, std::string("\n datalink.h")); if (setFiles.find("datalink.cpp") == setFiles.end()) ssSource.insert(nStop, std::string("\n datalink.cpp")); // Write the file again if needed if (nSourceSize != ssSource.size()) { std::ofstream stream; stream.open(pathFile, std::ofstream::trunc); if (!stream.is_open()) return; // TODO: Exception: throw CCompileException("Failed to open the CMakeLists.txt file for writing."); // Write the complete source stream << ssSource; } } CDbcUtilCMakeGenerator::~CDbcUtilCMakeGenerator() {}