diff --git a/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java index c714c0586a..fd98d78c8e 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java @@ -33,6 +33,7 @@ import org.eclipse.emf.ecore.resource.Resource; import org.lflang.FileConfig; import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CmakeInitIncludeProperty; import org.lflang.target.property.FilesProperty; import org.lflang.target.property.ProtobufsProperty; import org.lflang.util.FileUtil; @@ -102,7 +103,7 @@ public void doClean() throws IOException { * the generated .lf file for the federate. */ public void relativizePaths(FederateTargetConfig targetConfig) { - List.of(ProtobufsProperty.INSTANCE, FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE) + List.of(ProtobufsProperty.INSTANCE, FilesProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, CmakeInitIncludeProperty.INSTANCE) .forEach( p -> { if (targetConfig.isSet(p)) { diff --git a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java index 5931399052..837e6739de 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -37,6 +37,7 @@ import org.lflang.target.property.AuthProperty; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CmakeInitIncludeProperty; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; @@ -142,6 +143,11 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("cmake_minimum_required(VERSION " + MIN_CMAKE_VERSION + ")"); + // Add the cmake-init-include files + for (String includeFile : targetConfig.getOrDefault(CmakeInitIncludeProperty.INSTANCE)) { + cMakeCode.pr("include(\"" + Path.of(includeFile).getFileName() + "\")"); + } + // Setup the project header for different platforms switch (platformOptions.platform()) { case ZEPHYR: @@ -261,6 +267,11 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("endif()"); cMakeCode.pr("# Require C11"); + switch (platformOptions.platform()) { + case STM32F4: + cMakeCode.pr("enable_language(C CXX ASM)"); + break; + } cMakeCode.pr("set(CMAKE_C_STANDARD 11)"); cMakeCode.pr("set(CMAKE_C_STANDARD_REQUIRED ON)"); cMakeCode.newLine(); diff --git a/core/src/main/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index 12de4474dc..1467e9eb3c 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -244,9 +244,9 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). if (!fileConfig.srcPath.toString().contains("fed-gen")) { // Do not convert to Unix path - arguments.add("-DLF_SOURCE_DIRECTORY='" + quote + srcPath + quote + "'"); - arguments.add("-DLF_PACKAGE_DIRECTORY='" + quote + rootPath + quote + "'"); - arguments.add("-DLF_SOURCE_GEN_DIRECTORY='" + quote + srcGenPath + quote + "'"); + arguments.add("-DLF_SOURCE_DIRECTORY=" + srcPath); + arguments.add("-DLF_PACKAGE_DIRECTORY=" + rootPath); + arguments.add("-DLF_SOURCE_GEN_DIRECTORY=" + srcGenPath); } arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index dda5c06d89..dfcb09bd82 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -88,6 +88,7 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildCommandsProperty; import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CmakeInitIncludeProperty; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.FedSetupProperty; @@ -788,6 +789,15 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { true); } + if (targetConfig.isSet(CmakeInitIncludeProperty.INSTANCE)) { + FileUtil.copyFilesOrDirectories( + targetConfig.get(CmakeInitIncludeProperty.INSTANCE), + destination, + fileConfig, + messageReporter, + true); + } + try { var file = targetConfig.get(FedSetupProperty.INSTANCE); if (file != null) { @@ -926,6 +936,11 @@ protected void copyTargetFiles() throws IOException { FileUtil.copyFileFromClassPath( "/lib/platform/zephyr/Kconfig", fileConfig.getSrcGenPath(), true); } + case STM32F4 -> { + // Copy over STM32 library (Currently hard-coded) + FileUtil.copyFileFromClassPath( + "/lib/platform/stm32/arm-none-eabi-gcc.cmake", fileConfig.getSrcGenPath(), true); + } case RP2040 -> { // For the pico src-gen, copy over vscode configurations for debugging Path vscodePath = fileConfig.getSrcGenPath().resolve(".vscode"); diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index 53e3364cd0..a2772b0995 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -80,6 +80,10 @@ private String generateMainFunction() { case RP2040 -> { return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); } + + case STM32F4 -> { + return String.join("\n", "int main(void) {", " return lf_reactor_c_main(0, NULL);", "}"); + } default -> { return String.join( "\n", diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 30048f5a58..def719da17 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -34,6 +34,7 @@ import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.target.property.CmakeIncludeProperty; +import org.lflang.target.property.CmakeInitIncludeProperty; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.CoordinationOptionsProperty; @@ -589,6 +590,7 @@ public void initialize(TargetConfig config) { ClockSyncModeProperty.INSTANCE, ClockSyncOptionsProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, + CmakeInitIncludeProperty.INSTANCE, CompileDefinitionsProperty.INSTANCE, CompilerProperty.INSTANCE, CoordinationOptionsProperty.INSTANCE, @@ -608,6 +610,7 @@ public void initialize(TargetConfig config) { case CPP -> config.register( BuildTypeProperty.INSTANCE, + CmakeInitIncludeProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, CompilerProperty.INSTANCE, DockerProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/target/property/CmakeInitIncludeProperty.java b/core/src/main/java/org/lflang/target/property/CmakeInitIncludeProperty.java new file mode 100644 index 0000000000..2b9c903567 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CmakeInitIncludeProperty.java @@ -0,0 +1,47 @@ +package org.lflang.target.property; + +import java.util.List; + +import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; + +/** + * Directive to specify cmake initialize files to be included at the very beginning of the + * generated CMakeLists.txt. Here the user can override things like the toolchain file + */ + +public final class CmakeInitIncludeProperty extends FileListProperty { + + /** Singleton target property instance. */ + public static final CmakeInitIncludeProperty INSTANCE = new CmakeInitIncludeProperty(); + + private CmakeInitIncludeProperty() { + super(); + } + + @Override + protected List fromAst(Element node, MessageReporter reporter) { + return ASTUtils.elementToListOfStrings(node); + } + + @Override + protected List fromString(String string, MessageReporter reporter) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Element toAstElement(List value) { + return ASTUtils.toElement(value); + } + + @Override + public String name() { + return "cmake-init-include"; + } + + @Override + public boolean loadFromFederate() { + return true; + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/PlatformType.java b/core/src/main/java/org/lflang/target/property/type/PlatformType.java index 650a033b4c..277c066666 100644 --- a/core/src/main/java/org/lflang/target/property/type/PlatformType.java +++ b/core/src/main/java/org/lflang/target/property/type/PlatformType.java @@ -18,6 +18,7 @@ public enum Platform { LINUX("Linux"), MAC("Darwin"), ZEPHYR("Zephyr"), + STM32F4("STM32F4"), FLEXPRET("FlexPRET"), PATMOS("Patmos"), WINDOWS("Windows"); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt index c3ce84c747..29bc4d83a3 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppRos2PackageGenerator.kt @@ -4,6 +4,7 @@ import org.lflang.generator.PrependOperator import org.lflang.joinWithLn import org.lflang.target.property.BuildTypeProperty import org.lflang.target.property.CmakeIncludeProperty +import org.lflang.target.property.CmakeInitIncludeProperty import org.lflang.target.property.Ros2DependenciesProperty import org.lflang.target.property.RuntimeVersionProperty import org.lflang.toUnixString @@ -52,7 +53,7 @@ class CppRos2PackageGenerator(generator: CppGenerator, private val nodeName: Str fun generatePackageCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = (targetConfig.get(CmakeIncludeProperty.INSTANCE) + targetConfig.get(CmakeInitIncludeProperty.INSTANCE))?.map { fileConfig.srcPath.resolve(it).toUnixString() } return with(PrependOperator) { with(CppGenerator) { diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt index 2c041fe6d2..8428493377 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppStandaloneCmakeGenerator.kt @@ -28,10 +28,7 @@ import org.lflang.FileConfig import org.lflang.target.TargetConfig import org.lflang.generator.PrependOperator import org.lflang.joinWithLn -import org.lflang.target.property.BuildTypeProperty -import org.lflang.target.property.CmakeIncludeProperty -import org.lflang.target.property.ExternalRuntimePathProperty -import org.lflang.target.property.RuntimeVersionProperty +import org.lflang.target.property.* import org.lflang.toUnixString import java.nio.file.Path @@ -140,7 +137,7 @@ class CppStandaloneCmakeGenerator(private val targetConfig: TargetConfig, privat fun generateCmake(sources: List): String { // Resolve path to the cmake include files if any was provided - val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() } + val includeFiles = (targetConfig.get(CmakeIncludeProperty.INSTANCE) + targetConfig.get(CmakeInitIncludeProperty.INSTANCE))?.map { fileConfig.srcPath.resolve(it).toUnixString() } val reactorCppTarget = when { targetConfig.isSet(ExternalRuntimePathProperty.INSTANCE) -> "reactor-cpp" diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 3d7715c39f..335d52b7d2 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 3d7715c39fc40ad3c4c29918e724dc5b96738ca5 +Subproject commit 335d52b7d2aafaa794a7abb08fd2bcb1b8bf6603 diff --git a/core/src/main/resources/lib/platform/stm32/arm-none-eabi-gcc.cmake b/core/src/main/resources/lib/platform/stm32/arm-none-eabi-gcc.cmake new file mode 100644 index 0000000000..2e49051282 --- /dev/null +++ b/core/src/main/resources/lib/platform/stm32/arm-none-eabi-gcc.cmake @@ -0,0 +1,23 @@ +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR arm) + +# Some default GCC settings +set(TOOLCHAIN_PREFIX arm-none-eabi-) +set(FLAGS + "-fdata-sections -ffunction-sections \ + --specs=nano.specs -Wl,--gc-sections") +set(CPP_FLAGS + "-fno-rtti -fno-exceptions \ + -fno-threadsafe-statics") + +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc ${FLAGS}) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++ ${FLAGS} ${CPP_FLAGS}) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy) +set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size) + +set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) \ No newline at end of file diff --git a/test/C/src/FileReader.lf b/test/C/src/FileReader.lf index e802baf115..d1995358fa 100644 --- a/test/C/src/FileReader.lf +++ b/test/C/src/FileReader.lf @@ -6,7 +6,7 @@ reactor Source { reaction(startup) -> out {= char* file_path = - LF_SOURCE_DIRECTORY + "LF_SOURCE_DIRECTORY" LF_FILE_SEPARATOR "lib" LF_FILE_SEPARATOR "FileReader.txt";