diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java index 044290de91..20878ee217 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -28,7 +28,7 @@ import org.lflang.target.property.ClockSyncOptionsProperty; import org.lflang.target.property.ClockSyncOptionsProperty.ClockSyncOptions; import org.lflang.target.property.CmakeIncludeProperty; -import org.lflang.target.property.CommunicationTypeProperty; +import org.lflang.target.property.CommunicationModeProperty; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CoordinationOptionsProperty; import org.lflang.target.property.CoordinationProperty; @@ -202,9 +202,9 @@ public static void handleCompileDefinitions( if (federate.targetConfig.get(AuthProperty.INSTANCE)) { definitions.put("FEDERATED_AUTHENTICATED", ""); } - if (federate.targetConfig.isSet(CommunicationTypeProperty.INSTANCE)) { + if (federate.targetConfig.isSet(CommunicationModeProperty.INSTANCE)) { definitions.put( - "COMM_TYPE", federate.targetConfig.get(CommunicationTypeProperty.INSTANCE).toString()); + "COMM_TYPE", federate.targetConfig.get(CommunicationModeProperty.INSTANCE).toString()); } definitions.put("NUMBER_OF_FEDERATES", String.valueOf(federateNames.size())); definitions.put("EXECUTABLE_PREAMBLE", ""); diff --git a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java index e9379dd108..632860d20e 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedGenerator.java +++ b/core/src/main/java/org/lflang/federated/generator/FedGenerator.java @@ -59,12 +59,14 @@ import org.lflang.lf.VarRef; import org.lflang.target.Target; import org.lflang.target.TargetConfig; +import org.lflang.target.property.CommunicationModeProperty; import org.lflang.target.property.CoordinationProperty; import org.lflang.target.property.DockerProperty; import org.lflang.target.property.DockerProperty.DockerOptions; import org.lflang.target.property.KeepaliveProperty; import org.lflang.target.property.NoCompileProperty; import org.lflang.target.property.PlatformProperty; +import org.lflang.target.property.type.CommunicationModeType.CommunicationMode; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; import org.lflang.util.Averager; import org.lflang.util.FileUtil; @@ -159,6 +161,12 @@ public boolean doGenerate(Resource resource, LFGeneratorContext context) throws // for logical connections. replaceFederateConnectionsWithProxies(federation, main, resource); + // If communication mode is SST, generate configurations for SST. + if (context.getTargetConfig().get(CommunicationModeProperty.INSTANCE) + == CommunicationMode.SST) { + SSTGenerator.setupSST(fileConfig, federates, messageReporter, context, rtiConfig); + } + FedEmitter fedEmitter = new FedEmitter( fileConfig, 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..5ebe4ef34d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java +++ b/core/src/main/java/org/lflang/federated/generator/FederationFileConfig.java @@ -91,6 +91,26 @@ public Path getFedBinPath() { return getFedGenPath().resolve("bin"); } + public Path getSSTPath() { + return getGenPath().resolve("sst"); + } + + public Path getSSTConfigPath() { + return getSSTPath().resolve("configs"); + } + + public Path getSSTCredentialsPath() { + return getSSTPath().resolve("credentials"); + } + + public Path getSSTGraphsPath() { + return getSSTPath().resolve("graphs"); + } + + public Path getSSTAuthPath() { + return getSSTPath().resolve("auth"); + } + @Override public void doClean() throws IOException { super.doClean(); diff --git a/core/src/main/java/org/lflang/federated/generator/SSTGenerator.java b/core/src/main/java/org/lflang/federated/generator/SSTGenerator.java new file mode 100644 index 0000000000..ccad0d971c --- /dev/null +++ b/core/src/main/java/org/lflang/federated/generator/SSTGenerator.java @@ -0,0 +1,410 @@ +package org.lflang.federated.generator; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.lflang.MessageReporter; +import org.lflang.federated.launcher.RtiConfig; +import org.lflang.generator.LFGeneratorContext; +import org.lflang.target.property.SSTPathProperty; +import org.lflang.util.FileUtil; + +/** + * SST related methods. + * + * @author Dongha Kim + */ +public class SSTGenerator { + public static void setupSST( + FederationFileConfig fileConfig, + List federates, + MessageReporter messageReporter, + LFGeneratorContext context, + RtiConfig rtiConfig) { + if (context.getTargetConfig().get(SSTPathProperty.INSTANCE).isEmpty()) { + context + .getErrorReporter() + .nowhere() + .error( + "Target property `sst-root-path:` has not been defined. `comm-type: SST` requires" + + " `sst-root-path`"); + return; + } + + FileUtil.createDirectoryIfDoesNotExist(fileConfig.getSSTConfigPath().toFile()); + FileUtil.createDirectoryIfDoesNotExist(fileConfig.getSSTCredentialsPath().toFile()); + FileUtil.createDirectoryIfDoesNotExist(fileConfig.getSSTGraphsPath().toFile()); + + // Create graph used when creating credentials. + // Set graph path. + Path graphPath = fileConfig.getSSTGraphsPath().resolve(fileConfig.name + ".graph"); + // Generate the graph file content + JsonObject graphObject = SSTGenerator.generateGraphFile(federates, rtiConfig); + // Write the graph object to a JSON file + try (FileWriter fileWriter = new FileWriter(graphPath.toString())) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + gson.toJson(graphObject, fileWriter); + messageReporter + .nowhere() + .info("Graph file generated successfully into: " + graphPath.toString()); + } catch (IOException e) { + throw new RuntimeException(e); + } + + // Set root path to execute commands. + Path sstRepoRootPath = Paths.get(context.getTargetConfig().get(SSTPathProperty.INSTANCE)); + ProcessBuilder processBuilder = new ProcessBuilder(); + + // Set the working directory to the specified path + processBuilder.directory(sstRepoRootPath.resolve("examples").toFile()); + + // Clean the old credentials & generate new credentials. + // processBuilder.command("bash", "-c", "echo" + graphPath); + + processBuilder.command( + "bash", + "-c", + "echo \"Executing: ./cleanAll.sh ; ./generateAll.sh -g " + + graphPath + + " -p " + + fileConfig.name + + "\" && " + + "./cleanAll.sh ; ./generateAll.sh -g " + + graphPath + + " -p " + + fileConfig.name + + " && " + + "echo \"generateAll.sh finished successfully.\""); + + // Start the process + try { + Process process = processBuilder.start(); + + // Create threads to capture output and error streams + Thread outputThread = + new Thread( + () -> { + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + messageReporter.nowhere().info("[SST Script] " + line); + } + } catch (IOException e) { + e.printStackTrace(); + } + }); + + outputThread.start(); + + int exitCode = process.waitFor(); // Wait for process to finish + outputThread.join(); + + if (exitCode == 0) { + messageReporter.nowhere().info("Credential generation script execution succeeded."); + } else { + messageReporter.nowhere().error("Script execution failed with exit code: " + exitCode); + } + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + + // Copy credentials. + try { + SSTGenerator.copyCredentials(fileConfig, sstRepoRootPath); + messageReporter + .nowhere() + .info("Credentials copied into: " + fileConfig.getSSTCredentialsPath().toString()); + SSTGenerator.copyAuthNecessary(fileConfig, sstRepoRootPath); + messageReporter + .nowhere() + .info("Auth necessary files copied into: " + fileConfig.getSSTAuthPath().toString()); + SSTGenerator.updatePropertiesFile(fileConfig); + } catch (IOException e) { + throw new RuntimeException(e); + } + + // Generate SST config for the rti. + SSTGenerator.generateSSTConfig(fileConfig, "rti"); + messageReporter + .nowhere() + .info( + "Generated RTI's SST config into: " + + SSTGenerator.getSSTConfig(fileConfig, "rti").toString()); + + // Generate SST config for the federates. + for (FederateInstance federate : federates) { + SSTGenerator.generateSSTConfig(fileConfig, federate.name); + messageReporter + .nowhere() + .info( + "Federate generated SST config into: " + + SSTGenerator.getSSTConfig(fileConfig, federate.name).toString()); + } + } + + public static Path getSSTConfig(FederationFileConfig fileConfig, String name) { + return fileConfig.getSSTConfigPath().resolve(name + ".config"); + } + + private static void generateSSTConfig(FederationFileConfig fileConfig, String name) { + // Values to fill in + String entityName = "net1." + name; + String pubkeyRoot = + fileConfig.getSSTCredentialsPath().resolve("auth_certs").toString() + + File.separator + + "Auth101EntityCert.pem"; + String privkeyRoot = + fileConfig.getSSTCredentialsPath().resolve("keys").resolve("net1").toString() + + File.separator + + "Net1." + + name + + "Key.pem"; + String authIpAddress = "127.0.0.1"; + int authPortNumber = 21900; + String entityServerIpAddress = "127.0.0.1"; + int entityServerPortNumber = 15045; + String networkProtocol = "TCP"; + + // Create the configuration content + StringBuilder configContent = new StringBuilder(); + configContent + .append("entityInfo.name=") + .append(entityName) + .append("\n") + .append("entityInfo.purpose={\"group\":\"Servers\"}\n") + .append("entityInfo.number_key=1\n") + .append("authInfo.pubkey.path=") + .append(pubkeyRoot) + .append("\n") + .append("entityInfo.privkey.path=") + .append(privkeyRoot) + .append("\n") + .append("auth.ip.address=") + .append(authIpAddress) + .append("\n") + .append("auth.port.number=") + .append(authPortNumber) + .append("\n") + .append("entity.server.ip.address=") + .append(entityServerIpAddress) + .append("\n") + .append("entity.server.port.number=") + .append(entityServerPortNumber) + .append("\n") + .append("network.protocol=") + .append(networkProtocol) + .append("\n"); + + try { + // Create the new file and write the modified content + Path newFilePath; + newFilePath = fileConfig.getSSTConfigPath().resolve(name + ".config"); + // Create /SST directories if necessary + Files.createDirectories(newFilePath.getParent().getParent()); + // Create /SST/configs directories if necessary + Files.createDirectories(newFilePath.getParent()); // Create parent directories if necessary + BufferedWriter writer = new BufferedWriter(new FileWriter(newFilePath.toFile(), false)); + writer.write(configContent.toString()); + writer.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static JsonObject generateGraphFile( + List federateInstances, RtiConfig rtiConfig) { + JsonObject graphObject = new JsonObject(); + + // Auth list + JsonArray authList = new JsonArray(); + authList.add( + createAuthEntry(101, "localhost", "localhost", 21900, 21902, 21901, 21903, 1, false, true)); + authList.add( + createAuthEntry(102, "localhost", "localhost", 21900, 21902, 21901, 21903, 1, false, true)); + graphObject.add("authList", authList); + + // Auth trusts + JsonArray authTrusts = new JsonArray(); + JsonObject trustRelation = new JsonObject(); + trustRelation.addProperty("id1", 101); + trustRelation.addProperty("id2", 102); + authTrusts.add(trustRelation); + graphObject.add("authTrusts", authTrusts); + + // Assignments section + JsonObject assignments = new JsonObject(); + assignments.addProperty("net1.rti", 101); + for (FederateInstance federate : federateInstances) { + assignments.addProperty("net1." + federate.name, 101); // Assuming "101" is a placeholder + } + graphObject.add("assignments", assignments); + + // Entity list section + JsonArray entityList = createEntityList(federateInstances, rtiConfig); + graphObject.add("entityList", entityList); + + // File sharing lists (empty for this example) + graphObject.add("filesharingLists", new JsonArray()); + + return graphObject; + } + + private static JsonObject createAuthEntry( + int id, + String entityHost, + String authHost, + int tcpPort, + int udpPort, + int authPort, + int callbackPort, + int dbProtectionMethod, + boolean backupEnabled, + boolean contextualCallbackEnabled) { + JsonObject authEntry = new JsonObject(); + authEntry.addProperty("id", id); + authEntry.addProperty("entityHost", entityHost); + authEntry.addProperty("authHost", authHost); + authEntry.addProperty("tcpPort", tcpPort); + authEntry.addProperty("udpPort", udpPort); + authEntry.addProperty("authPort", authPort); + authEntry.addProperty("callbackPort", callbackPort); + authEntry.addProperty("dbProtectionMethod", dbProtectionMethod); + authEntry.addProperty("backupEnabled", backupEnabled); + authEntry.addProperty("contextualCallbackEnabled", contextualCallbackEnabled); + return authEntry; + } + + private static JsonArray createEntityList( + List federateInstances, RtiConfig rtiConfig) { + JsonArray entityList = new JsonArray(); + + // RTI entity + JsonObject rti = createEntity("Servers", "net1.rti", "Net1.rti"); + rti.addProperty("port", rtiConfig.getPort()); + rti.addProperty("host", rtiConfig.getHost()); + entityList.add(rti); + + // Federate entities + for (FederateInstance federate : federateInstances) { + String federateName = federate.name; + JsonObject entity = createEntity("Clients", "net1." + federateName, "Net1." + federateName); + entityList.add(entity); + } + return entityList; + } + + private static JsonObject createEntity(String group, String name, String credentialPrefix) { + JsonObject entity = new JsonObject(); + entity.addProperty("group", group); + entity.addProperty("name", name); + entity.addProperty("distProtocol", "TCP"); + entity.addProperty("usePermanentDistKey", false); + entity.addProperty("distKeyValidityPeriod", "1*hour"); + entity.addProperty("maxSessionKeysPerRequest", 1); + entity.addProperty("netName", "net1"); + entity.addProperty("credentialPrefix", credentialPrefix); + // Add distributionCryptoSpec + JsonObject distributionCryptoSpec = new JsonObject(); + distributionCryptoSpec.addProperty("cipher", "AES-128-CBC"); + distributionCryptoSpec.addProperty("mac", "SHA256"); + entity.add("distributionCryptoSpec", distributionCryptoSpec); + + // Add sessionCryptoSpec + JsonObject sessionCryptoSpec = new JsonObject(); + sessionCryptoSpec.addProperty("cipher", "AES-128-CBC"); + sessionCryptoSpec.addProperty("mac", "SHA256"); + entity.add("sessionCryptoSpec", sessionCryptoSpec); + + entity.addProperty("host", "localhost"); + entity.add("backupToAuthIds", new JsonArray()); // Empty array for backupToAuthIds + return entity; + } + + private static void copyCredentials(FederationFileConfig fileConfig, Path sstRepoRootPath) + throws IOException { + // Copy auth_certs. + Path source1 = sstRepoRootPath.resolve("entity").resolve("auth_certs"); + Path destination1 = fileConfig.getSSTCredentialsPath().resolve("auth_certs"); + + // Copy keys. + Path source2 = sstRepoRootPath.resolve("entity").resolve("credentials").resolve("keys"); + Path destination2 = fileConfig.getSSTCredentialsPath().resolve("keys"); + FileUtil.copyDirectoryContents(source1, destination1, false); + FileUtil.copyDirectoryContents(source2, destination2, false); + } + + private static void copyAuthNecessary(FederationFileConfig fileConfig, Path sstRepoRootPath) + throws IOException { + // Copy Auth credentials. + Path source1 = sstRepoRootPath.resolve("auth").resolve("credentials").resolve("ca"); + Path destination1 = fileConfig.getSSTAuthPath().resolve("credentials").resolve("ca"); + + // Copy Auth databases. + Path source2 = sstRepoRootPath.resolve("auth").resolve("databases"); + Path destination2 = fileConfig.getSSTAuthPath().resolve("databases"); + + // Copy Auth properties. + Path source3 = sstRepoRootPath.resolve("auth").resolve("properties"); + Path destination3 = fileConfig.getSSTAuthPath().resolve("properties"); + + FileUtil.copyDirectoryContents(source1, destination1, false); + FileUtil.copyDirectoryContents(source2, destination2, false); + FileUtil.copyDirectoryContents(source3, destination3, false); + } + + private static void updatePropertiesFile(FederationFileConfig fileConfig) throws IOException { + File file = + Paths.get( + fileConfig.getSSTAuthPath().resolve("properties").toString(), + "exampleAuth101.properties") + .toFile(); + List updatedLines = new ArrayList<>(); + String sstAuthPathStr = fileConfig.getSSTAuthPath().toString(); + + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("entity_key_store_path=")) { + line = updatePath(line, sstAuthPathStr); + } else if (line.startsWith("internet_key_store_path=")) { + line = updatePath(line, sstAuthPathStr); + } else if (line.startsWith("database_key_store_path=")) { + line = updatePath(line, sstAuthPathStr); + } else if (line.startsWith("database_encryption_key_path=")) { + line = updatePath(line, sstAuthPathStr); + } else if (line.startsWith("trusted_ca_cert_paths=")) { + line = updatePath(line, sstAuthPathStr); + } else if (line.startsWith("auth_database_dir=")) { + line = updatePath(line, sstAuthPathStr); + } + updatedLines.add(line); + } + } + + // Write the updated lines back to the file + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + for (String updatedLine : updatedLines) { + writer.write(updatedLine); + writer.newLine(); + } + } + } + + private static String updatePath(String line, String sstAuthPathStr) { + return line.replace("../", sstAuthPathStr + "/"); + } +} diff --git a/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java b/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java index f2211577ac..edf0ad8eb8 100644 --- a/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java +++ b/core/src/main/java/org/lflang/federated/launcher/CBuildConfig.java @@ -28,7 +28,10 @@ import org.lflang.MessageReporter; import org.lflang.federated.generator.FederateInstance; import org.lflang.federated.generator.FederationFileConfig; +import org.lflang.federated.generator.SSTGenerator; import org.lflang.generator.c.CCompiler; +import org.lflang.target.property.CommunicationModeProperty; +import org.lflang.target.property.type.CommunicationModeType.CommunicationMode; /** * Utility class that can be used to create a launcher for federated LF programs that are written in @@ -55,6 +58,14 @@ public String compileCommand() { @Override public String localExecuteCommand() { - return fileConfig.getFedBinPath().resolve(federate.name) + " -i $FEDERATION_ID"; + String commandToReturn = + fileConfig.getFedBinPath().resolve(federate.name) + " -i $FEDERATION_ID"; + if (federate.targetConfig.get(CommunicationModeProperty.INSTANCE) == CommunicationMode.SST) { + commandToReturn = + commandToReturn + + " -sst " + + SSTGenerator.getSSTConfig(fileConfig, federate.name).toString(); + } + return commandToReturn; } } diff --git a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java index 192dcef334..e9441ad830 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -36,13 +36,17 @@ import org.lflang.MessageReporter; import org.lflang.federated.generator.FederateInstance; import org.lflang.federated.generator.FederationFileConfig; +import org.lflang.federated.generator.SSTGenerator; import org.lflang.target.TargetConfig; import org.lflang.target.property.AuthProperty; import org.lflang.target.property.ClockSyncModeProperty; import org.lflang.target.property.ClockSyncOptionsProperty; +import org.lflang.target.property.CommunicationModeProperty; import org.lflang.target.property.DNETProperty; +import org.lflang.target.property.SSTPathProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.type.ClockSyncModeType.ClockSyncMode; +import org.lflang.target.property.type.CommunicationModeType.CommunicationMode; /** * Utility class that can be used to create a launcher for federated LF programs. @@ -117,6 +121,9 @@ public void doGenerate(List federates, RtiConfig rtiConfig) { StringBuilder distCode = new StringBuilder(); shCode.append(getSetupCode()).append("\n"); String distHeader = getDistHeader(); + if (targetConfig.get(CommunicationModeProperty.INSTANCE) == CommunicationMode.SST) { + shCode.append(getSSTAuthExecutionCode()).append("\n"); + } String host = rtiConfig.getHost(); String target = host; @@ -267,6 +274,10 @@ public void doGenerate(List federates, RtiConfig rtiConfig) { } private String getSetupCode() { + String killAuthCommand = + (targetConfig.get(CommunicationModeProperty.INSTANCE) == CommunicationMode.SST) + ? " printf \"#### Killing Auth %s.\\n\" ${AUTH}\n kill ${AUTH} || true\n" + : ""; return String.join( "\n", "#!/bin/bash -l", @@ -284,7 +295,7 @@ private String getSetupCode() { " if [ \"$EXITED_SUCCESSFULLY\" = true ] ; then", " exit 0", " else", - " printf \"Killing federate %s.\\n\" ${pids[*]}", + killAuthCommand + " printf \"Killing federate %s.\\n\" ${pids[*]}", " # The || true clause means this is not an error if kill fails.", " kill ${pids[@]} || true", " printf \"#### Killing RTI %s.\\n\" ${RTI}", @@ -302,6 +313,32 @@ private String getSetupCode() { "# Launch the federates:"); } + private String getSSTAuthExecutionCode() { + String authLaunchCode = + "java -jar " + + targetConfig.get(SSTPathProperty.INSTANCE) + + "/auth/auth-server/target/auth-server-jar-with-dependencies.jar -p " + + fileConfig.getSSTAuthPath().toString() + + "/properties/exampleAuth101.properties --password=" + + fileConfig.name; + + String launchCodeWithLogging = String.join(" ", authLaunchCode, ">& auth.log &"); + String launchCodeWithoutLogging = String.join(" ", authLaunchCode, "&"); + + return String.join( + "\n", + "\n# Prompt for the password before starting SST Auth", + "echo \"Executing Auth.\"", + "# Launch the SST Auth.", + "if [ \"$1\" = \"-l\" ]; then", + launchCodeWithLogging, + "else", + launchCodeWithoutLogging, + "fi", + "# Store the PID of the Auth", + "AUTH=$!"); + } + private String getDistHeader() { return String.join( "\n", @@ -324,6 +361,12 @@ private String getRtiCommand(List federates, boolean isRemote) if (targetConfig.getOrDefault(TracingProperty.INSTANCE).isEnabled()) { commands.add(" -t \\"); } + if (targetConfig.get(CommunicationModeProperty.INSTANCE) == CommunicationMode.SST) { + commands.add( + " -sst " + + SSTGenerator.getSSTConfig(fileConfig, "rti").toString() + + " \\"); + } if (!targetConfig.getOrDefault(DNETProperty.INSTANCE)) { commands.add(" -d \\"); } 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 8ae70cec44..b6a33bc10f 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -37,7 +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.CommunicationTypeProperty; +import org.lflang.target.property.CommunicationModeProperty; import org.lflang.target.property.CompileDefinitionsProperty; import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; @@ -46,6 +46,7 @@ import org.lflang.target.property.SingleThreadedProperty; import org.lflang.target.property.TracePluginProperty; import org.lflang.target.property.WorkersProperty; +import org.lflang.target.property.type.CommunicationModeType.CommunicationMode; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; @@ -427,8 +428,15 @@ CodeBuilder generateCMakeCode( cMakeCode.pr("target_link_libraries( ${LF_MAIN_TARGET} PRIVATE OpenSSL::SSL)"); cMakeCode.newLine(); } - if (targetConfig.isSet(CommunicationTypeProperty.INSTANCE)) { - cMakeCode.pr("set(COMM_TYPE " + targetConfig.get(CommunicationTypeProperty.INSTANCE) + ")"); + if (targetConfig.isSet(CommunicationModeProperty.INSTANCE)) { + cMakeCode.pr("set(COMM_TYPE " + targetConfig.get(CommunicationModeProperty.INSTANCE) + ")"); + cMakeCode.newLine(); + } + if (targetConfig.get(CommunicationModeProperty.INSTANCE) == CommunicationMode.SST) { + // If communication mode is SST, find sst package. + cMakeCode.pr("# Find sst-c-api and link to it."); + cMakeCode.pr("find_package(sst-lib REQUIRED)"); + cMakeCode.pr("target_link_libraries(${LF_MAIN_TARGET} PRIVATE sst-lib::sst-c-api)"); cMakeCode.newLine(); } 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 cb1ff1eace..46507a06ce 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -925,6 +925,9 @@ protected void copyTargetFiles() throws IOException { "logging", "platform", "low_level_platform", "trace", "version", "tag", "network")) { var entry = "/lib/c/reactor-c/" + directory; if (arduino) { + if ("network".equals(directory)) { + continue; // Skip copying for the "network" directory + } if (FileConfig.class.getResource(entry + "/api") != null) { FileUtil.copyFromClassPath( entry + "/api", diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 1b8445abfd..6102a7cc20 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -556,7 +556,8 @@ public void initialize(TargetConfig config) { ClockSyncModeProperty.INSTANCE, ClockSyncOptionsProperty.INSTANCE, CmakeIncludeProperty.INSTANCE, - CommunicationTypeProperty.INSTANCE, + CommunicationModeProperty.INSTANCE, + SSTPathProperty.INSTANCE, CompileDefinitionsProperty.INSTANCE, CompilerProperty.INSTANCE, CoordinationOptionsProperty.INSTANCE, diff --git a/core/src/main/java/org/lflang/target/property/CommunicationModeProperty.java b/core/src/main/java/org/lflang/target/property/CommunicationModeProperty.java new file mode 100644 index 0000000000..f4aade96c3 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/CommunicationModeProperty.java @@ -0,0 +1,43 @@ +package org.lflang.target.property; + +import org.lflang.MessageReporter; +import org.lflang.ast.ASTUtils; +import org.lflang.lf.Element; +import org.lflang.target.property.type.CommunicationModeType; +import org.lflang.target.property.type.CommunicationModeType.CommunicationMode; + +public final class CommunicationModeProperty + extends TargetProperty { + + /** Singleton target property instance. */ + public static final CommunicationModeProperty INSTANCE = new CommunicationModeProperty(); + + private CommunicationModeProperty() { + super(new CommunicationModeType()); + } + + @Override + public Element toAstElement(CommunicationMode value) { + return ASTUtils.toElement(value.toString()); + } + + @Override + public CommunicationMode initialValue() { + return CommunicationMode.TCP; + } + + @Override + public CommunicationMode fromAst(Element node, MessageReporter reporter) { + return fromString(ASTUtils.elementToSingleString(node), reporter); + } + + @Override + protected CommunicationMode fromString(String string, MessageReporter reporter) { + return this.type.forName(string); + } + + @Override + public String name() { + return "comm-type"; + } +} diff --git a/core/src/main/java/org/lflang/target/property/CommunicationTypeProperty.java b/core/src/main/java/org/lflang/target/property/CommunicationTypeProperty.java deleted file mode 100644 index 47e7d29ac9..0000000000 --- a/core/src/main/java/org/lflang/target/property/CommunicationTypeProperty.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.lflang.target.property; - -import org.lflang.MessageReporter; -import org.lflang.ast.ASTUtils; -import org.lflang.lf.Element; -import org.lflang.target.property.type.CommunicationTypeType; -import org.lflang.target.property.type.CommunicationTypeType.CommunicationType; - -/** Directive to specify the target communication type such as 'TCP', 'SST', or 'MQTT'. */ -public final class CommunicationTypeProperty - extends TargetProperty { - - /** Singleton target property instance. */ - public static final CommunicationTypeProperty INSTANCE = new CommunicationTypeProperty(); - - private CommunicationTypeProperty() { - super(new CommunicationTypeType()); - } - - @Override - public Element toAstElement(CommunicationType value) { - return ASTUtils.toElement(value.toString()); - } - - @Override - public CommunicationType initialValue() { - return CommunicationType.TCP; - } - - @Override - public CommunicationType fromAst(Element node, MessageReporter reporter) { - return fromString(ASTUtils.elementToSingleString(node), reporter); - } - - @Override - protected CommunicationType fromString(String string, MessageReporter reporter) { - return this.type.forName(string); - } - - @Override - public String name() { - return "comm-type"; - } -} diff --git a/core/src/main/java/org/lflang/target/property/SSTPathProperty.java b/core/src/main/java/org/lflang/target/property/SSTPathProperty.java new file mode 100644 index 0000000000..721cc492ea --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/SSTPathProperty.java @@ -0,0 +1,17 @@ +package org.lflang.target.property; + +/** The compiler to invoke, unless a build command has been specified. */ +public final class SSTPathProperty extends StringProperty { + + /** Singleton target property instance. */ + public static final SSTPathProperty INSTANCE = new SSTPathProperty(); + + private SSTPathProperty() { + super(); + } + + @Override + public String name() { + return "sst-root-path"; + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/CommunicationModeType.java b/core/src/main/java/org/lflang/target/property/type/CommunicationModeType.java new file mode 100644 index 0000000000..4de1d16293 --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/type/CommunicationModeType.java @@ -0,0 +1,43 @@ +package org.lflang.target.property.type; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.lflang.target.property.type.CommunicationModeType.CommunicationMode; + +/** Enumeration of communication types */ +public class CommunicationModeType extends OptionsType { + + @Override + protected Class enumClass() { + return CommunicationMode.class; + } + + /** Enumeration of communication types. */ + public enum CommunicationMode { + TCP("TCP"), + SST("SST"); + + /** Alias used in toString method. */ + private final String alias; + + /** Private constructor for Cmake build types. */ + CommunicationMode(String alias) { + this.alias = alias; + } + + /** Return the alias. */ + @Override + public String toString() { + return this.alias; + } + + public static List optionsList() { + return Arrays.stream(CommunicationMode.values()).collect(Collectors.toList()); + } + + public static CommunicationMode getDefault() { + return CommunicationMode.TCP; + } + } +} diff --git a/core/src/main/java/org/lflang/target/property/type/CommunicationTypeType.java b/core/src/main/java/org/lflang/target/property/type/CommunicationTypeType.java deleted file mode 100644 index b2c146330e..0000000000 --- a/core/src/main/java/org/lflang/target/property/type/CommunicationTypeType.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.lflang.target.property.type; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import org.lflang.target.property.type.CommunicationTypeType.CommunicationType; - -/** Enumeration of communication types */ -public class CommunicationTypeType extends OptionsType { - - @Override - protected Class enumClass() { - return CommunicationType.class; - } - - /** Enumeration of communication types. */ - public enum CommunicationType { - TCP("TCP"), - SST("SST"), - MQTT("MQTT"); - - /** Alias used in toString method. */ - private final String alias; - - /** Private constructor for Cmake build types. */ - CommunicationType(String alias) { - this.alias = alias; - } - - /** Return the alias. */ - @Override - public String toString() { - return this.alias; - } - - public static List optionsList() { - return Arrays.stream(CommunicationType.values()).collect(Collectors.toList()); - } - - public static CommunicationType getDefault() { - return CommunicationType.TCP; - } - } -} diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index aca13882a4..b4720bb0ce 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit aca13882a4da7003f17224f014e4363e3977ece7 +Subproject commit b4720bb0ce367c673d39fe0b4dd516406c6e8d18 diff --git a/core/src/main/resources/lib/cpp/reactor-cpp b/core/src/main/resources/lib/cpp/reactor-cpp index e0df4349bb..d255a3da57 160000 --- a/core/src/main/resources/lib/cpp/reactor-cpp +++ b/core/src/main/resources/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit e0df4349bb5726e659d5c6589fa948a18991e2b8 +Subproject commit d255a3da57d38db2988bcab68024b0a77ccc8657 diff --git a/core/src/main/resources/lib/rs/reactor-rs b/core/src/main/resources/lib/rs/reactor-rs index 10fee74e32..9fe7853ecd 160000 --- a/core/src/main/resources/lib/rs/reactor-rs +++ b/core/src/main/resources/lib/rs/reactor-rs @@ -1 +1 @@ -Subproject commit 10fee74e32a72f15ec3bc5605d61c27f63c8e037 +Subproject commit 9fe7853ecdbf6d33f6916ad5f822c6d9dd01609d diff --git a/core/src/main/resources/lib/rs/runtime-version.properties b/core/src/main/resources/lib/rs/runtime-version.properties index 2e9a7684bd..96314e5bac 100644 --- a/core/src/main/resources/lib/rs/runtime-version.properties +++ b/core/src/main/resources/lib/rs/runtime-version.properties @@ -1 +1 @@ -rs = bca71291d2b9547863bd42171872203336e9ec3f +rs = 9fe7853ecdbf6d33f6916ad5f822c6d9dd01609d