Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed docker file generation for C/Ccpp target and python target #700

Merged
merged 14 commits into from
Nov 1, 2021
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Containerized distributed LF program where a MessageGenerator creates a string
* message that is sent via the RTI (runtime infrastructure) to a
* receiver that prints the message.
*
* For run instructions, see README.
*
* @author Edward A. Lee
*/
target C {
timeout: 10 secs,
docker: true
};

import MessageGenerator from "../HelloWorld.lf"
import PrintMessage from "../HelloWorld.lf"

federated reactor HelloWorldContainerized at rti {
source = new MessageGenerator(prefix = "Hello World");
print = new PrintMessage();
source.message -> print.message;
}
51 changes: 51 additions & 0 deletions example/C/src/DistributedHelloWorld/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# ContainerizedFederatedHelloWorld
This is a basic example showing containerized federated execution.

For more details, see: [Containerized Execution in Lingua Franca](https://github.com/lf-lang/lingua-franca/wiki/Containerized-Execution)

## Run instructions
Put HelloWorld.lf in a src directory.
Then, run:
```bash
lfc HelloWorldContainerized.lf
```

There would be 3 build messages, 1 for the RTI and 2 for the reactors, indicating where the docker file is generated, as well as the instruction to build the docker file.

A message would look something like this:
```
Dockerfile for <something> written to <some_directory>/<name_of_dockerfile>
#####################################
To build the docker image, use:

docker build -t <some_name> -f <some_directory>/<name_of_dockerfile> <some_path>

#####################################
```

If you cannot find the build message for the RTI, try a clean build using:
```bash
lfc --clean HelloWorld.lf
```

Then, use the printed commands to build the 3 docker images.

Set up a docker network using
```bash
docker network create lf
```

Open 3 terminals, 1 for the RTI and 1 for each reactor.

Run the RTI:
```bash
docker run --rm -it --network=lf --name=rti rti -i 1 -n 2
```

Run the two reactors:
```bash
docker run --rm -it --network=lf helloworldcontainerized_source -i 1
```
```bash
docker run --rm -it --network=lf helloworldcontainerized_print -i 1
```
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/TargetProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public enum TargetProperty {
* true or false, or a dictionary of options.
*/
DOCKER("docker", UnionType.DOCKER_UNION,
Arrays.asList(Target.C, Target.CCPP), (config, value, err) -> {
Arrays.asList(Target.C, Target.CCPP, Target.Python), (config, value, err) -> {
if (value.getLiteral() != null) {
if (ASTUtils.toBoolean(value)) {
config.dockerOptions = new DockerOptions();
Expand Down
28 changes: 28 additions & 0 deletions org.lflang/src/org/lflang/generator/GeneratorBase.xtend
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,34 @@ abstract class GeneratorBase extends AbstractLFValidator implements TargetTypes
return false
}

/**
* Copy the core files needed to build the RTI within a container.
*
* @param the directory where rti.Dockerfile is located.
* @param the core files used for code generation in the current target.
*/
def copyRtiFiles(File rtiDir, ArrayList<String> coreFiles) {
var rtiFiles = newArrayList()
rtiFiles.addAll(coreFiles)

// add the RTI files on top of the coreFiles
rtiFiles.addAll(
"federated/RTI/rti.h",
"federated/RTI/rti.c",
"federated/RTI/CMakeLists.txt"
)
fileConfig.copyFilesFromClassPath("/lib/c/reactor-c/core", rtiDir + File.separator + "core", rtiFiles)
}

/**
* Write a Dockerfile for the current federate as given by filename.
* @param the name given to the docker file (without any extension).
*/
def writeDockerFile(String dockerFileName) {
throw new UnsupportedOperationException("This target does not support docker file generation.")
}


/**
* Parsed error message from a compiler is returned here.
*/
Expand Down
47 changes: 45 additions & 2 deletions org.lflang/src/org/lflang/generator/PythonGenerator.xtend
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ class PythonGenerator extends CGenerator {
targetConfig.noCompile = compileStatus

if (errorsOccurred) return;

var baseFileName = topLevelName
for (federate : federates) {
if (isFederated) {
Expand Down Expand Up @@ -1092,7 +1092,6 @@ class PythonGenerator extends CGenerator {
printRunInfo();
}
}

}
// Restore filename
topLevelName = baseFileName
Expand Down Expand Up @@ -1699,6 +1698,50 @@ class PythonGenerator extends CGenerator {
}
}

/**
* Write a Dockerfile for the current federate as given by filename.
* The file will go into src-gen/filename.Dockerfile.
* If there is no main reactor, then no Dockerfile will be generated
* (it wouldn't be very useful).
* @param The root filename (without any extension).
*/
override writeDockerFile(String filename) {
var srcGenPath = fileConfig.getSrcGenPath
val dockerFile = srcGenPath + File.separator + filename + '.Dockerfile'
// If a dockerfile exists, remove it.
var file = new File(dockerFile)
housengw marked this conversation as resolved.
Show resolved Hide resolved
if (file.exists) {
file.delete
}

if (this.mainDef === null) {
return
}

val contents = new StringBuilder()
pr(contents, '''
# Generated docker file for «topLevelName».lf in «srcGenPath».
# For instructions, see: https://github.com/icyphy/lingua-franca/wiki/Containerized-Execution
FROM python:alpine
WORKDIR /lingua-franca/«topLevelName»
COPY . src-gen
RUN set -ex && apk add --no-cache gcc musl-dev \
&& cd src-gen && python3 setup.py install && cd .. \
&& apk del gcc musl-dev
ENTRYPOINT ["python3", "src-gen/«filename».py"]
''')
writeSourceCodeToFile(contents.toString.getBytes, dockerFile)
println("Dockerfile written to " + dockerFile)
println('''
#####################################
To build the docker image, use:

docker build -t «topLevelName.toLowerCase()» -f «dockerFile» «srcGenPath»

#####################################
''')
}

/**
* Convert C types to formats used in Py_BuildValue and PyArg_PurseTuple.
* This is unused but will be useful to enable inter-compatibility between
Expand Down
Loading