diff --git a/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java b/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java index 424568109a..29e62e835b 100644 --- a/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java +++ b/core/src/integrationTest/java/org/lflang/tests/RunSingleTest.java @@ -49,7 +49,7 @@ public class RunSingleTest { private static final Pattern TEST_FILE_PATTERN = - Pattern.compile("(test/(\\w+))/src/([^/]++/)*(\\w+.lf)"); + Pattern.compile("(test\\W(\\w+))\\Wsrc\\W(\\w++\\W)*(\\w+.lf)"); @Test public void runSingleTest() throws FileNotFoundException { diff --git a/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java b/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java index 09f7fac34f..98f1c16ad6 100644 --- a/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java +++ b/core/src/main/java/org/lflang/federated/launcher/PyBuildConfig.java @@ -12,26 +12,12 @@ public PyBuildConfig( } @Override - public String localExecuteCommand() { - return "python3 " - + fileConfig.getSrcGenPath() - + "/" - + federate.name - + "/" - + federate.name - + ".py -i $FEDERATION_ID"; + public String remoteExecuteCommand() { + return "bin/" + fileConfig.name + "_" + federate.name + " -i '$FEDERATION_ID'"; } @Override - public String remoteExecuteCommand() { - return "python3 src-gen/" - + fileConfig.name - + "/" - + federate.name - + "/" - + fileConfig.name - + "_" - + federate.name - + " -i '$FEDERATION_ID'"; + public String localExecuteCommand() { + return fileConfig.getFedBinPath().resolve(federate.name) + " -i $FEDERATION_ID"; } } diff --git a/core/src/main/java/org/lflang/generator/python/PyFileConfig.java b/core/src/main/java/org/lflang/generator/python/PyFileConfig.java index 7c67b92493..3927b6d02e 100644 --- a/core/src/main/java/org/lflang/generator/python/PyFileConfig.java +++ b/core/src/main/java/org/lflang/generator/python/PyFileConfig.java @@ -2,10 +2,9 @@ import java.io.IOException; import java.nio.file.Path; -import java.util.List; import org.eclipse.emf.ecore.resource.Resource; +import org.lflang.generator.GeneratorUtils; import org.lflang.generator.c.CFileConfig; -import org.lflang.util.LFCommand; public class PyFileConfig extends CFileConfig { public PyFileConfig(Resource resource, Path srcGenBasePath, boolean useHierarchicalBin) @@ -13,19 +12,8 @@ public PyFileConfig(Resource resource, Path srcGenBasePath, boolean useHierarchi super(resource, srcGenBasePath, useHierarchicalBin); } - @Override - public LFCommand getCommand() { - return LFCommand.get( - "python3", List.of(srcPkgPath.relativize(getExecutable()).toString()), true, srcPkgPath); - } - - @Override - public Path getExecutable() { - return srcGenPath.resolve(name + getExecutableExtension()); - } - @Override protected String getExecutableExtension() { - return ".py"; + return GeneratorUtils.isHostWindows() ? ".bat" : ""; } } diff --git a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java index b8b3a74282..16615bb59e 100644 --- a/core/src/main/java/org/lflang/generator/python/PythonGenerator.java +++ b/core/src/main/java/org/lflang/generator/python/PythonGenerator.java @@ -37,6 +37,7 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.xbase.lib.Exceptions; import org.lflang.AttributeUtils; +import org.lflang.FileConfig; import org.lflang.Target; import org.lflang.TargetProperty; import org.lflang.ast.ASTUtils; @@ -100,8 +101,7 @@ public PythonGenerator(LFGeneratorContext context) { "lib/python_time.c", "lib/pythontarget.c"), PythonGenerator::setUpMainTarget, - "install(TARGETS)" // No-op - )); + generateCmakeInstall(context.getFileConfig()))); } private PythonGenerator( @@ -396,15 +396,10 @@ public void doGenerate(Resource resource, LFGeneratorContext context) { codeMaps.putAll(codeMapsForFederate); copyTargetFiles(); new PythonValidator(fileConfig, messageReporter, codeMaps, protoNames).doValidate(context); - if (targetConfig.noCompile) { - messageReporter.nowhere().info(PythonInfoGenerator.generateSetupInfo(fileConfig)); - } } catch (Exception e) { //noinspection ConstantConditions throw Exceptions.sneakyThrow(e); } - - messageReporter.nowhere().info(PythonInfoGenerator.generateRunInfo(fileConfig, lfModuleName)); } if (messageReporter.getErrorsOccurred()) { @@ -578,7 +573,7 @@ private static String setUpMainTarget( add_subdirectory(core) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}) set(LF_MAIN_TARGET ) - find_package(Python 3.7.0...<3.11.0 COMPONENTS Interpreter Development) + find_package(Python 3.10.0...<3.11.0 REQUIRED COMPONENTS Interpreter Development) Python_add_library( ${LF_MAIN_TARGET} MODULE @@ -598,11 +593,34 @@ private static String setUpMainTarget( target_link_libraries(${LF_MAIN_TARGET} PRIVATE ${Python_LIBRARIES}) target_compile_definitions(${LF_MAIN_TARGET} PUBLIC MODULE_NAME=) """) - .replace("", generatePythonModuleName(executableName)) - .replace("executableName", executableName); + .replace("", generatePythonModuleName(executableName)); // The use of fileConfig.name will break federated execution, but that's fine } + private static String generateCmakeInstall(FileConfig fileConfig) { + final var pyMainPath = + fileConfig.getSrcGenPath().resolve(fileConfig.name + ".py").toAbsolutePath(); + // need to replace '\' with '\\' on Windwos for proper escaping in cmake + final var pyMainName = pyMainPath.toString().replace("\\", "\\\\"); + return """ + if(WIN32) + file(GENERATE OUTPUT .bat CONTENT + "@echo off\n\ + ${Python_EXECUTABLE} %*" + ) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/.bat DESTINATION ${CMAKE_INSTALL_BINDIR}) + else() + file(GENERATE OUTPUT CONTENT + "#!/bin/sh\\n\\ + ${Python_EXECUTABLE} \\\"$@\\\"" + ) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() + """ + .replace("", fileConfig.name) + .replace("", pyMainName); + } + /** * Generate a ({@code key}, {@code val}) tuple pair for the {@code define_macros} field of the * Extension class constructor from setuptools. diff --git a/core/src/main/java/org/lflang/generator/python/PythonInfoGenerator.java b/core/src/main/java/org/lflang/generator/python/PythonInfoGenerator.java deleted file mode 100644 index 01cadbcc5c..0000000000 --- a/core/src/main/java/org/lflang/generator/python/PythonInfoGenerator.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.lflang.generator.python; - -import java.io.File; -import org.lflang.FileConfig; - -public class PythonInfoGenerator { - /** - * Print information about necessary steps to install the supporting Python C extension for the - * generated program. - * - * @note Only needed if no-compile is set to true - */ - public static String generateSetupInfo(FileConfig fileConfig) { - return String.join( - "\n", - "", - "#####################################", - "To compile and install the generated code, do:", - " ", - " cd " + fileConfig.getSrcGenPath() + File.separator, - " python3 -m pip install --force-reinstall .", - ""); - } - - /** Print information on how to execute the generated program. */ - public static String generateRunInfo(FileConfig fileConfig, String lfModuleName) { - return String.join( - "\n", - "", - "#####################################", - "To run the generated program, use:", - " ", - " python3 " + fileConfig.getSrcGenPath() + File.separator + lfModuleName + ".py", - "", - "#####################################", - ""); - } - - /** Print information on how to execute the generated federation. */ - public static String generateFedRunInfo(FileConfig fileConfig) { - return String.join( - "\n", - "", - "#####################################", - "To run the generated program, run:", - " ", - " bash " + fileConfig.binPath + "/" + fileConfig.name, - "", - "#####################################", - ""); - } -}