Commit 9eb8b761 authored by Evgeny Kusmenko's avatar Evgeny Kusmenko
Browse files

Merge branch 'richter-dev' into 'master'

Richter dev

See merge request !14
parents a7aa7101 f508cb56
Pipeline #64187 passed with stage
in 2 minutes and 44 seconds
![pipeline](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Cpp/badges/master/build.svg)
![coverage](https://git.rwth-aachen.de/monticore/EmbeddedMontiArc/generators/EMAM2Cpp/badges/master/coverage.svg)
[![PPTX-Docu](https://img.shields.io/badge/PPTX--Docu-2018--05--22-brightgreen.svg)](https://github.com/EmbeddedMontiArc/Documentation/blob/master/reposlides/18.05.22.Docu.EMAM2CPP.pdf)
[![PPTX-Docu](https://img.shields.io/badge/PPTX--Docu-2018--05--22-brightgreen.svg)](https://github.com/EmbeddedMontiArc/Documentation/blob/master/reposlides/18.05.22.Docu.EMAM2CPP.pdf)
# EMAM2Cpp
##CMake Generation:
* Available since version 0.0.22-SNAPSHOT.
* If `isGenerateCMakeEnabled()` additionally to the C++ files _CMakeLists.txt_ is generated.
This CMake file builds a static library out of the generated components.
* Find package (https://cmake.org/cmake/help/v3.8/command/find_package.html?highlight=i) can be configured via public method `getCMakeConfig()` from the generator class. FindModule files are generated automatically which searches for header include directories and libraries at default locations.
* Example: `getCMakeConfig().addModuleDependency(new CMakeFindModule("LibName", "LibHeader.hpp", "libname", headerSearchPaths, bibrarySearchPaths, findHeaderEnabled, findLibEnabled, isRequiered));`
\ No newline at end of file
......@@ -8,7 +8,7 @@
<groupId>de.monticore.lang.monticar</groupId>
<artifactId>embedded-montiarc-math-generator</artifactId>
<version>0.0.21-SNAPSHOT</version>
<version>0.0.22-SNAPSHOT</version>
<!-- == PROJECT DEPENDENCIES ============================================= -->
......
package de.monticore.lang.monticar.generator.cmake;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.monticar.generator.cpp.template.TemplateHelper;
import de.se_rwth.commons.logging.Log;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* Class to configure cmake file generation.
* Is responsible for generating the cmake files from freemarker templates.
* CMake dependencies to other modules can be added as Find Package file.
* See also https://cmake.org/cmake/help/v3.8/command/find_package.html?highlight=i
*
* @author Christoph Richter
*/
public class CMakeConfig {
private static final Template CMAKE_LISTS_CPP;
private static final Template CMAKE_FIND_PACKAGE;
static {
Configuration conf = new Configuration(Configuration.VERSION_2_3_23);
conf.setDefaultEncoding("UTF-8");
conf.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
conf.setLogTemplateExceptions(false);
conf.setClassForTemplateLoading(AllTemplates.class, "/template/cmake/");
try {
CMAKE_LISTS_CPP = conf.getTemplate("CMakeListsCppTemplate.ftl");
CMAKE_FIND_PACKAGE = conf.getTemplate("CMakeFindPackageTemplate.ftl");
} catch (IOException e) {
String msg = "could not load cmake templates";
Log.error(msg, e);
throw new RuntimeException(msg, e);
}
}
// fields
private CMakeListsCPPViewModel cMakeListsViewModel = new CMakeListsCPPViewModel();
private HashSet<CMakeFindModule> moduleList = new HashSet<>();
// constructor
public CMakeConfig(String compName) {
cMakeListsViewModel.setCompName(compName);
cMakeListsViewModel.setModuleDependencies(moduleList);
}
// methods
protected void configureCMakeListsViewModel() {
// nothing here
}
public List<FileContent> generateCMakeFiles() {
List<FileContent> files = new ArrayList<FileContent>();
// generate CMakeLists.txt
files.add(generateCMakeLists());
// generate FindModule.cmake's
for (CMakeFindModule module : moduleList) {
files.add(generateCMakeFindPackage(module));
}
return files;
}
private FileContent generateCMakeFindPackage(CMakeFindModule module) {
FileContent result = null;
// map data
Map<String, Object> dataForTemplate = TemplateHelper.getDataForTemplate(module);
// try generate file content
try {
StringWriter sw = new StringWriter();
CMAKE_FIND_PACKAGE.process(dataForTemplate, sw);
result = (new FileContent(sw.toString(), "/cmake/" + module.getFileName()));
} catch (TemplateException | IOException e) {
Log.error("CMakeFindPackage template generation failed. ", e);
}
return result;
}
public FileContent generateCMakeLists() {
FileContent result = null;
configureCMakeListsViewModel();
// map data
Map<String, Object> dataForTemplate = TemplateHelper.getDataForTemplate(cMakeListsViewModel);
// try generate file content
try {
StringWriter sw = new StringWriter();
CMAKE_LISTS_CPP.process(dataForTemplate, sw);
result = (new FileContent(sw.toString(), "/" + cMakeListsViewModel.CMAKELISTS_FILE_NAME));
} catch (TemplateException | IOException e) {
Log.error("CMakeLists template generation failed. ", e);
}
return result;
}
public void addModuleDependency(CMakeFindModule module) {
moduleList.add(module);
}
public CMakeListsCPPViewModel getCMakeListsViewModel() {
return cMakeListsViewModel;
}
}
package de.monticore.lang.monticar.generator.cmake;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ViewModelBase;
import java.util.ArrayList;
import java.util.List;
/**
* Representation of CMake Find files as Java class.
* Additionally acts as view model for the corresponding freemarker template.
*
* @author Christoph Richter
*/
public class CMakeFindModule extends ViewModelBase {
// fields
private String packageName;
private String includeName;
private String libName;
private List<String> includePaths = new ArrayList<>();
private List<String> libPaths = new ArrayList<>();
private Boolean findPath;
private Boolean findLibrary;
private boolean required;
public CMakeFindModule(String moduleName, Boolean required) {
this.packageName = moduleName;
this.required = required;
// guess rest
this.includeName = moduleName.toLowerCase();
this.libName = moduleName.toLowerCase();
findPath = true;
findLibrary = true;
}
public CMakeFindModule(String packageName, String includeName, String libName, List<String> includePaths, List<String> libPaths, Boolean findPath, Boolean findLibrary, boolean required) {
this.packageName = packageName;
this.includeName = includeName;
this.libName = libName;
this.includePaths = includePaths;
this.libPaths = libPaths;
this.findPath = findPath;
this.findLibrary = findLibrary;
this.required = required;
}
// methods
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getIncludeName() {
return includeName;
}
public void setIncludeName(String includeName) {
this.includeName = includeName;
}
public String getLibName() {
return libName;
}
public void setLibName(String libName) {
this.libName = libName;
}
public boolean isRequired() {
return required;
}
public void setRequired(boolean required) {
this.required = required;
}
public List<String> getIncludePaths() {
return includePaths;
}
public void setIncludePaths(List<String> includePaths) {
this.includePaths = includePaths;
}
public List<String> getLibPaths() {
return libPaths;
}
public void setLibPaths(List<String> libPaths) {
this.libPaths = libPaths;
}
public String getFileName() {
return String.format("Find%s.cmake", packageName);
}
public Boolean getFindPath() {
return findPath;
}
public void setFindPath(Boolean findPath) {
this.findPath = findPath;
}
public Boolean getFindLibrary() {
return findLibrary;
}
public void setFindLibrary(Boolean findLibrary) {
this.findLibrary = findLibrary;
}
}
package de.monticore.lang.monticar.generator.cmake;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ViewModelBase;
import java.util.HashSet;
/**
* View model which is used by the freemarker template
*
* @author Christoph Richter
*/
public class CMakeListsCPPViewModel extends ViewModelBase {
// const
public static final String CMAKELISTS_FILE_NAME = "CMakeLists.txt";
// fields
private String compName;
private HashSet<CMakeFindModule> moduleDependencies;
// methods
public String getCompName() {
return compName;
}
public void setCompName(String compName) {
this.compName = compName;
}
public HashSet<CMakeFindModule> getModuleDependencies() {
return moduleDependencies;
}
public void setModuleDependencies(HashSet<CMakeFindModule> moduleDependencies) {
this.moduleDependencies = moduleDependencies;
}
}
......@@ -2,15 +2,12 @@ package de.monticore.lang.monticar.generator.cpp;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.math._symboltable.MathStatementsSymbol;
import de.monticore.lang.monticar.generator.BluePrint;
import de.monticore.lang.monticar.generator.FileContent;
import de.monticore.lang.monticar.generator.Generator;
import de.monticore.lang.monticar.generator.Helper;
import de.monticore.lang.monticar.generator.MathCommandRegister;
import de.monticore.lang.monticar.generator.*;
import de.monticore.lang.monticar.generator.cmake.CMakeConfig;
import de.monticore.lang.monticar.generator.cmake.CMakeFindModule;
import de.monticore.lang.monticar.generator.cpp.converter.MathConverter;
import de.monticore.lang.monticar.generator.cpp.converter.TypeConverter;
import de.monticore.lang.monticar.generator.cpp.template.AllTemplates;
import de.monticore.lang.monticar.generator.cpp.viewmodel.AutopilotAdapterViewModel;
import de.monticore.lang.monticar.generator.cpp.viewmodel.ServerWrapperViewModel;
import de.monticore.lang.monticar.ts.MCTypeSymbol;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
......@@ -48,6 +45,10 @@ public class GeneratorCPP implements Generator {
protected boolean generateSimulatorInterface = false;
protected boolean checkModelDir = false;
// CMake
private boolean generateCMake = false;
private CMakeConfig cMakeConfig;
public GeneratorCPP() {
this.mathCommandRegister = new MathCommandRegisterCPP();
useOctaveBackend();
......@@ -55,13 +56,26 @@ public class GeneratorCPP implements Generator {
currentInstance = this;
}
protected void setupCMake() {
cMakeConfig = new CMakeConfig("");
if (usesArmadilloBackend()) {
// add dependency on module Armadillo
cMakeConfig.addModuleDependency(new CMakeFindModule("Armadillo", true));
}
}
public void useArmadilloBackend() {
MathConverter.curBackend = new ArmadilloBackend();
setupCMake();
}
public boolean usesArmadilloBackend() {
return MathConverter.curBackend instanceof ArmadilloBackend;
}
public void useOctaveBackend() {
MathConverter.curBackend = new OctaveBackend();
setupCMake();
//Log.warn("This backend has been deprecated. Armadillo is the recommended backend now.");
}
......@@ -164,10 +178,26 @@ public class GeneratorCPP implements Generator {
setGenerationTargetPath(getGenerationTargetPath() + "/");
}
List<File> files = saveFilesToDisk(fileContents);
//cmake
if (generateCMake)
files.addAll(generateCMakeFiles(componentSymbol));
return files;
}
protected List<File> generateCMakeFiles(ExpandedComponentInstanceSymbol componentInstanceSymbol) {
List<File> files = new ArrayList<>();
cMakeConfig.getCMakeListsViewModel().setCompName(componentInstanceSymbol.getFullName().replace('.', '_').replace('[', '_').replace(']', '_'));
List<FileContent> contents = cMakeConfig.generateCMakeFiles();
try {
for (FileContent content : contents)
files.add(generateFile(content));
} catch (IOException e) {
e.printStackTrace();
}
return files;
}
public List<File> saveFilesToDisk(List<FileContent> fileContents) throws IOException {
List<File> files = new ArrayList<>();
for (FileContent fileContent : fileContents) {
......@@ -365,11 +395,26 @@ public class GeneratorCPP implements Generator {
private static FileContent generateServerWrapper(ExpandedComponentInstanceSymbol componentSymbol) {
return generateWrapper(componentSymbol, "server.cc");
}
private static FileContent generateWrapper(ExpandedComponentInstanceSymbol componentSymbol, String name) {
private static FileContent generateWrapper(ExpandedComponentInstanceSymbol componentSymbol, String name) {
ServerWrapperViewModel vm = new ServerWrapperViewModel();
vm.setMainModelName(GeneralHelperMethods.getTargetLanguageComponentName(componentSymbol.getFullName()));
String fileContents = AllTemplates.generateServerWrapper(vm);
return new FileContent(fileContents, name);
}
public boolean isGenerateCMakeEnabled() {
return generateCMake;
}
public void setGenerateCMake(boolean generateCMake) {
if (!this.generateCMake && generateCMake)
setupCMake();
this.generateCMake = generateCMake;
}
public CMakeConfig getCMakeConfig() {
return cMakeConfig;
}
}
# Automatically generated file
#
# - Try to find ${viewModel.packageName}
# Once done this will define
# ${viewModel.packageName}_FOUND - System has ${viewModel.packageName}
# ${viewModel.packageName}_INCLUDE_DIRS - The ${viewModel.packageName} include directories
# ${viewModel.packageName}_LIBRARY_DIRS - The library directories needed to use ${viewModel.packageName}
# ${viewModel.packageName}_LIBRARIES - The libraries needed to use ${viewModel.packageName}
<#if viewModel.findPath>
find_path(${viewModel.packageName}_INCLUDE_DIR
NAMES ${viewModel.includeName}
PATH_SUFFIXES "include"
PATHS
<#list viewModel.includePaths as var>
\" ${var} \"
</#list>
)
</#if>
<#if viewModel.findLibrary>
find_library(${viewModel.packageName}_LIBRARY
NAMES ${viewModel.libName}
PATH_SUFFIXES "lib" "lib64" "lib/x86_64-linux-gnu" "examples/lib_win64" "build"
PATHS
<#list viewModel.libPaths as var>
\" ${var} \"
</#list>
)
</#if>
include(FindPackageHandleStandardArgs)
# if all listed variables are TRUE
find_package_handle_standard_args(
${viewModel.packageName}
DEFAULT_MSG
<#if viewModel.findPath>${viewModel.packageName}_INCLUDE_DIR</#if>
<#if viewModel.findLibrary>${viewModel.packageName}_LIBRARY</#if>
)
mark_as_advanced(
<#if viewModel.findPath>${viewModel.packageName}_INCLUDE_DIR</#if>
<#if viewModel.findLibrary>${viewModel.packageName}_LIBRARY</#if>
)
<#if viewModel.findPath>set(${viewModel.packageName}_INCLUDE_DIRS ${r"${"}${viewModel.packageName}${r"_INCLUDE_DIR}"})</#if>
<#if viewModel.findLibrary>set(${viewModel.packageName}_LIBRARIES ${r"${"}${viewModel.packageName}${r"_LIBRARY}"})</#if>
\ No newline at end of file
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11)
project(${viewModel.compName} LANGUAGES CXX)
#set cmake module path
set(CMAKE_MODULE_PATH ${r"${CMAKE_MODULE_PATH}"} ${r"${CMAKE_CURRENT_SOURCE_DIR}"}/cmake)
# add dependencies
<#list viewModel.moduleDependencies as var>
find_package(${var.packageName} <#if var.required>REQUIRED<#else>OPTIONAL</#if>)
<#if var.findPath>set(INCLUDE_DIRS ${r"${INCLUDE_DIRS}"} ${r"${"}${var.packageName}${r"_INCLUDE_DIRS}"})</#if>
<#if var.findLibrary>set(LIBS ${r"${LIBS}"} ${r"${"}${var.packageName}${r"_LIBRARIES}"})</#if>
</#list>
# create static library
include_directories(${r"${INCLUDE_DIRS}"})
add_library(${viewModel.compName} ${viewModel.compName}.h)
target_include_directories(${viewModel.compName} PUBLIC ${r"${CMAKE_CURRENT_SOURCE_DIR}"})
target_link_libraries(${viewModel.compName} PUBLIC ${r"${LIBS}"})
set_target_properties(${viewModel.compName} PROPERTIES LINKER_LANGUAGE CXX)
# export cmake project
export(TARGETS ${viewModel.compName} FILE ${viewModel.compName}.cmake)
package de.monticore.lang.monticar.generator.cmake;
import de.monticore.lang.embeddedmontiarc.embeddedmontiarc._symboltable.ExpandedComponentInstanceSymbol;
import de.monticore.lang.monticar.generator.AbstractSymtabTest;
import de.monticore.lang.monticar.generator.cpp.GeneratorCPP;
import de.monticore.lang.tagging._symboltable.TaggingResolver;
import de.se_rwth.commons.logging.Log;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertNotNull;
/**
* Tests the generation of cmake files
*
* @author Christoph Richter
*/
public class GenerateCMakeTest extends AbstractSymtabTest {
private static TaggingResolver symtab;
private static GeneratorCPP generatorCPP;
@Before
public void setUpClass() {
Log.enableFailQuick(false);
symtab = createSymTabAndTaggingResolver("src/test/resources");
generatorCPP = new GeneratorCPP();
generatorCPP.useArmadilloBackend();
generatorCPP.setGenerateCMake(true);
}
@Test
public void testCMakeGenerationForBasicConstantAssignment() throws IOException {
ExpandedComponentInstanceSymbol componentSymbol = symtab.<ExpandedComponentInstanceSymbol>resolve("test.basicConstantAssignment", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentSymbol);
generatorCPP.setGenerationTargetPath("./target/generated-sources-cpp/cmake/test/BasicConstantAssignment");
List<File> files = generatorCPP.generateFiles(componentSymbol, symtab);
String restPath = "cmake/test/BasicConstantAssignment/";
testCMakeFilesEqual(files, restPath);
}
@Test
public void testCMakeGenerationForModel() throws IOException {
ExpandedComponentInstanceSymbol componentSymbol = symtab.<ExpandedComponentInstanceSymbol>resolve("testing.model", ExpandedComponentInstanceSymbol.KIND).orElse(null);
assertNotNull(componentSymbol);
generatorCPP.setGenerationTargetPath("./target/generated-sources-cpp/cmake/testing/Model");
List<File> files = generatorCPP.generateFiles(componentSymbol, symtab);
String restPath = "cmake/testing/Model/";
testCMakeFilesEqual(files, restPath);
}
private void testCMakeFilesEqual(List<File> files, String restPath) {
List<File> srcFiles = new ArrayList<>();
List<File> findFiles = new ArrayList<>();
for (File f : files) {
if (f.getName().startsWith("Find"))
findFiles.add(f);
else
srcFiles.add(f);
}
testFilesAreEqual(srcFiles, restPath);
testFilesAreEqual(findFiles, restPath + "cmake/");
}
}
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11)
project(test_basicConstantAssignment LANGUAGES CXX)
#set cmake module path
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
# add dependencies
find_package(Armadillo REQUIRED)
set(INCLUDE_DIRS ${INCLUDE_DIRS} ${Armadillo_INCLUDE_DIRS})
set(LIBS ${LIBS} ${Armadillo_LIBRARIES})
# create static library
include_directories(${INCLUDE_DIRS})
add_library(test_basicConstantAssignment test_basicConstantAssignment.h)
target_include_directories(test_basicConstantAssignment PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(test_basicConstantAssignment PUBLIC ${LIBS})
set_target_properties(test_basicConstantAssignment PROPERTIES LINKER_LANGUAGE CXX)
# export cmake project
export(TARGETS test_basicConstantAssignment FILE test_basicConstantAssignment.cmake)