Skip to content

Commit

Permalink
Add support for compiling FMUs using docker
Browse files Browse the repository at this point in the history
For example using the following:
```mo
buildModelFMU(M, platforms={"arm-linux-gnueabihf docker run
  docker.openmodelica.org/armcross-omsimulator:v2.0"}
```

Belonging to [master]:
  - OpenModelica/OMCompiler#2545
  - OpenModelica/OpenModelica-testsuite#987
  • Loading branch information
sjoelund authored and OpenModelica-Hudson committed Jun 30, 2018
1 parent 3f36b04 commit 7660aa0
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 38 deletions.
89 changes: 56 additions & 33 deletions Compiler/Script/CevalScriptBackend.mo
Expand Up @@ -3347,21 +3347,25 @@ protected function configureFMU
input String logfile;
input Boolean isWindows;
protected
String CC, CFLAGS, LDFLAGS, makefileStr,
String CC, CFLAGS, LDFLAGS, makefileStr, container, host, nozip,
dir=fmutmp+"/sources/", cmd="",
quote="'",
dquote = if isWindows then "\"" else "'";
list<String> rest;
Boolean finishedBuild;
Integer uid;
algorithm
CC := System.getCCompiler();
CFLAGS := "-Os "+System.stringReplace(System.getCFlags(),"${MODELICAUSERCFLAGS}","");
LDFLAGS := ("-L"+dquote+Settings.getInstallationDirectoryPath()+"/lib/"+System.getTriple()+"/omc"+dquote+" "+
"-Wl,-rpath,"+dquote+Settings.getInstallationDirectoryPath()+"/lib/"+System.getTriple()+"/omc"+dquote+" "+
System.getLDFlags()+" ");
if System.regularFileExists(dir + logfile) then
System.removeFile(dir + logfile);
if System.regularFileExists(logfile) then
System.removeFile(logfile);
end if;
_ := match platform
case "dynamic"
nozip := System.getMakeCommand()+" -j"+intString(Config.noProc()) + " nozip";
finishedBuild := match Util.stringSplitAtChar(platform, " ")
case {"dynamic"}
algorithm
makefileStr := System.readFile(dir + "Makefile.in");
// replace @XX@ variables in the Makefile
Expand All @@ -3379,8 +3383,8 @@ algorithm
System.writeFile(dir + "Makefile", makefileStr);
System.writeFile(dir + "config.log", "Using cached values for dynamic platform");
cmd := "cached values";
then ();
case "static"
then false;
case {"static"}
algorithm
makefileStr := System.readFile(dir + "Makefile.in");
// replace @XX@ variables in the Makefile
Expand All @@ -3398,24 +3402,49 @@ algorithm
System.writeFile(dir + "Makefile", makefileStr);
System.writeFile(dir + "config.log", "Using cached values for static platform");
cmd := "cached values";
then ();
else
then false;
case {_}
algorithm
cmd := "cd \"" + fmutmp + "/sources\" && ./configure --host="+quote+platform+quote+" CFLAGS="+quote+"-Os"+quote+" LDFLAGS=";
cmd := "cd \"" + fmutmp + "/sources\" && ./configure --host="+quote+platform+quote+" CFLAGS="+quote+"-Os"+quote+" LDFLAGS= && " +
nozip;
if 0 <> System.systemCall(cmd, outFile=logfile) then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {System.readFile(logfile)});
System.removeFile(dir + logfile);
fail();
end if;
then ();
then true;
case host::"docker"::"run"::rest
algorithm
uid := System.getuid();
cmd := "docker run "+(if uid<>0 then "--user " + String(uid) else "")+" --rm -w /fmu -v "+quote+System.realpath(fmutmp+"/..")+quote+":/fmu " +stringDelimitList(rest," ")+ " sh -c " + dquote +
"cd " + dquote + System.basename(fmutmp) + "/sources" + dquote + " && " +
"./configure --host="+quote+host+quote+" CFLAGS="+quote+"-Os"+quote+" LDFLAGS= && " +
nozip + dquote;
if 0 <> System.systemCall(cmd, outFile=logfile) then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {System.readFile(logfile)});
System.removeFile(dir + logfile);
fail();
end if;
then true;
else
algorithm
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {"Unknown platform (contains spaces but does does not conform to \"platform docker run [args] container\""});
then fail();
end match;
if not isWindows then
if 0 <> System.systemCall("cd " + dir + " && make clean > /dev/null 2>&1") then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {"Failed to make clean"});
ExecStat.execStat("buildModelFMU: configured platform " + platform + " using " + cmd);
if not finishedBuild then
if not isWindows then
if 0 <> System.systemCall("cd " + dir + " && make clean > /dev/null 2>&1") then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {"Failed to make clean"});
fail();
end if;
end if;
if 0 <> System.systemCall("cd \"" + fmutmp + "/sources\" && " + nozip, outFile=logfile) then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {System.readFile(logfile)});
System.removeFile(dir + logfile);
fail();
end if;
end if;
ExecStat.execStat("buildModelFMU: configured platform " + platform + " using " + cmd);
end configureFMU;

protected function buildModelFMU " author: Frenkel TUD
Expand Down Expand Up @@ -3503,28 +3532,22 @@ algorithm
logfile := filenameprefix + ".log";
dir := fmutmp+"/sources/";

if listEmpty(platforms) then
cmd := "rm -f \"" + filenameprefix + ".fmu\" && cd \"" + fmutmp + "\" && zip -r \"../" + filenameprefix + ".fmu\" *";
if 0 <> System.systemCall(cmd, outFile=logfile) then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {System.readFile(logfile)});
ExecStat.execStat("buildModelFMU failed for no platform");
end if;
return;
end if;

for platform in platforms loop
configureFMU(platform, fmutmp, logfile, isWindows);
try
CevalScript.compileModel(filenameprefix, libs, workingDir=dir, makeVars={});
else
outValue := Values.STRING("");
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {System.readFile(logfile)});
ExecStat.execStat("buildModelFMU failed for platform " + platform);
return;
end try;
configureFMU(platform, fmutmp, System.realpath(fmutmp)+"/resources/"+System.stringReplace(listGet(Util.stringSplitAtChar(platform," "),1),"/","-")+".log", isWindows);
ExecStat.execStat("buildModelFMU: Generate platform " + platform);
end for;

cmd := "rm -f \"" + filenameprefix + ".fmu\" && cd \"" + fmutmp + "\" && zip -r \"../" + fmuTargetName + ".fmu\" *";
if 0 <> System.systemCall(cmd, outFile=logfile) then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {cmd + "\n\n" + System.readFile(logfile)});
ExecStat.execStat("buildModelFMU failed");
end if;

if not System.regularFileExists(fmuTargetName + ".fmu") then
Error.addMessage(Error.SIMULATOR_BUILD_ERROR, {"Build commands returned success, but " + filenameprefix + ".fmu does not exist"});
fail();
end if;

System.removeDirectory(fmutmp);
end buildModelFMU;

Expand Down
11 changes: 6 additions & 5 deletions Compiler/Template/CodegenFMU.tpl
Expand Up @@ -1140,20 +1140,21 @@ match platform
>>
else
<<
<%fileNamePrefix%>_FMU: $(MAINOBJ) <%fileNamePrefix%>_functions.h <%fileNamePrefix%>_literals.h $(OFILES) $(RUNTIMEFILES)
<%fileNamePrefix%>_FMU: nozip
<%\t%>cd .. && rm -f ../<%fileNamePrefix%>.fmu && zip -r ../<%fmuTargetName%>.fmu *
nozip: $(MAINOBJ) <%fileNamePrefix%>_functions.h <%fileNamePrefix%>_literals.h $(OFILES) $(RUNTIMEFILES)
<%\t%>mkdir -p ../binaries/$(FMIPLATFORM)
ifeq (@LIBTYPE_DYNAMIC@,1)
<%\t%>$(LD) -o <%modelNamePrefix%>$(DLLEXT) $(MAINOBJ) $(OFILES) $(RUNTIMEFILES) <%dirExtra%> <%libsPos1%> <%libsPos2%> $(LDFLAGS)
<%\t%>cp <%fileNamePrefix%>$(DLLEXT) <%fileNamePrefix%>_FMU.libs config.log ../binaries/$(FMIPLATFORM)/
<%\t%>cp <%fileNamePrefix%>$(DLLEXT) <%fileNamePrefix%>_FMU.libs ../binaries/$(FMIPLATFORM)/
endif
<%\t%>head -n20 Makefile > ../binaries/$(FMIPLATFORM)/config.summary
<%\t%>head -n20 Makefile > ../resources/$(FMIPLATFORM).summary
ifeq (@LIBTYPE_STATIC@,1)
<%\t%>rm -f <%modelNamePrefix%>.a
<%\t%>$(AR) -rsu <%modelNamePrefix%>.a $(MAINOBJ) $(OFILES) $(RUNTIMEFILES)
<%\t%>cp <%fileNamePrefix%>.a <%fileNamePrefix%>_FMU.libs config.log ../binaries/$(FMIPLATFORM)/
<%\t%>cp <%fileNamePrefix%>.a <%fileNamePrefix%>_FMU.libs ../binaries/$(FMIPLATFORM)/
endif
<%\t%>$(MAKE) distclean
<%\t%>cd .. && rm -f ../<%fileNamePrefix%>.fmu && zip -r ../<%fmuTargetName%>.fmu *
distclean: clean
<%\t%>rm -f Makefile config.status config.log
clean:
Expand Down
5 changes: 5 additions & 0 deletions Compiler/Util/System.mo
Expand Up @@ -736,6 +736,11 @@ Consider opening a socket and letting anyone run system() commands without authe
external "C" isRoot=System_userIsRoot() annotation(Library = "omcruntime");
end userIsRoot;

public function getuid
output Integer uid;
external "C" uid=System_getuid() annotation(Library = "omcruntime");
end getuid;

public function configureCommandLine
"Returns the date and command used to configure OpenModelica.
On the platforms that don't configure options, like OMDev, the returned string
Expand Down
8 changes: 8 additions & 0 deletions Compiler/Util/Util.mo
Expand Up @@ -961,6 +961,14 @@ algorithm
end try;
end writeFileOrErrorMsg;

public function stringStartsWith
input String inString1;
input String inString2;
output Boolean outEqual;
algorithm
outEqual := (0 == System.strncmp(inString1, inString2, stringLength(inString1)));
end stringStartsWith;

public function strncmp "Compare two strings up to the nth character
Returns true if they are equal."
input String inString1;
Expand Down
9 changes: 9 additions & 0 deletions Compiler/runtime/System_omc.c
Expand Up @@ -538,6 +538,15 @@ extern int System_userIsRoot()
return CONFIG_USER_IS_ROOT;
}

extern int System_getuid()
{
#if defined(__MINGW32__) || defined(_MSC_VER)
return 0;
#else
return getuid();
#endif
}

extern const char* System_readEnv(const char *envname)
{
char *envvalue = getenv(envname);
Expand Down

0 comments on commit 7660aa0

Please sign in to comment.