Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ jobs:
- os: windows-latest
version: '1.10'
lib_subdir: 'x86_64-mingw32'
shim_ext: '.dll'
- os: ubuntu-latest
version: '1.10'
lib_subdir: 'x86_64-linux-gnu'
shim_ext: '.so'
- os: macos-latest
version: '1.10'
lib_subdir: 'aarch64-apple-darwin'
shim_ext: '.dylib'
steps:
- uses: actions/checkout@v4

Expand All @@ -46,6 +52,32 @@ jobs:
Pkg.build()
'

- name: Build ModelicaCallbacks shim (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
gcc -shared -fPIC -o lib/ext/shared/${{ matrix.lib_subdir }}/libModelicaCallbacks.so src/modelica_callbacks.c -ldl

- name: Build ModelicaCallbacks shim (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
mkdir -p lib/ext/shared/${{ matrix.lib_subdir }}
cc -dynamiclib -fPIC -o lib/ext/shared/${{ matrix.lib_subdir }}/libModelicaCallbacks.dylib src/modelica_callbacks.c -ldl

- name: Build ModelicaCallbacks shim (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
mkdir -p lib/ext/shared/${{ matrix.lib_subdir }}
gcc -shared -o lib/ext/shared/${{ matrix.lib_subdir }}/libModelicaCallbacks.dll src/modelica_callbacks.c -lpsapi

- name: Upload shim artifact
uses: actions/upload-artifact@v4
with:
name: libModelicaCallbacks-${{ matrix.lib_subdir }}
path: lib/ext/shared/${{ matrix.lib_subdir }}/libModelicaCallbacks${{ matrix.shim_ext }}

- name: Run tests (Linux)
if: runner.os == 'Linux'
shell: bash
Expand All @@ -56,6 +88,16 @@ jobs:
Pkg.test()
'

- name: Run tests (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
export DYLD_LIBRARY_PATH="$(pwd)/lib/ext/shared/${{ matrix.lib_subdir }}:${DYLD_LIBRARY_PATH}"
julia --color=yes --project -e '
import Pkg
Pkg.test()
'

- name: Run tests (Windows)
if: runner.os == 'Windows'
shell: bash
Expand All @@ -66,3 +108,35 @@ jobs:
import Pkg
Pkg.test()
'

release:
name: Release dynamic libraries
needs: test
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
steps:
- name: Download all shim artifacts
uses: actions/download-artifact@v4
with:
pattern: libModelicaCallbacks-*
path: artifacts

- name: Package per platform
shell: bash
run: |
for dir in artifacts/*/; do
platform=$(basename "$dir" | sed 's/^libModelicaCallbacks-//')
cd "$dir"
tar -czvf "../../${platform}-callbacks.tar.gz" *
cd ../..
done

- name: Create release
uses: marvinpinto/action-automatic-releases@latest
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
draft: false
prerelease: false
title: "ModelicaCallbacks Shim ${{ github.ref_name }}"
files: |
*-callbacks.tar.gz
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "OMRuntimeExternalC"
uuid = "ada38df0-e20e-11ed-02f3-2b4b19c1ec8a"
authors = ["Adrian Pop <adrian.pop@liu.se>", "John Tinnerholm <john.tinnerholm@liu.se>"]
version = "0.1.0"
version = "0.2.0"

[deps]
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
Expand Down
75 changes: 65 additions & 10 deletions deps/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,29 @@

using HTTP
import ZipFile
import Tar
import Inflate

const DEPS_DIR = @__DIR__
const PACKAGE_DIR = dirname(DEPS_DIR)
const PATH_TO_EXT = joinpath(PACKAGE_DIR, "lib", "ext")
const RELEASE_BASE_URL = "https://github.com/OpenModelica/OMRuntimeExternalC.jl/releases/download/libs-v0.1.0"
const CALLBACKS_VERSION = "v0.1.0"
const CALLBACKS_BASE_URL = "https://github.com/OpenModelica/OMRuntimeExternalC.jl/releases/download/$(CALLBACKS_VERSION)"

function downloadAndExtractLibraries(libraryString; URL)
@info "Downloading archive from $(URL)..."

#= Ensure the lib/ext directory exists =#
mkpath(PATH_TO_EXT)

local zipPath = joinpath(PATH_TO_EXT, libraryString * ".zip")
HTTP.download(URL, zipPath)

#= Create shared directory if it does not exist =#
local sharedDir = joinpath(PATH_TO_EXT, "shared")
mkpath(sharedDir)

@info "Extracting to $(sharedDir)..."
r = ZipFile.Reader(zipPath)
for f in r.files
#= Skip directory entries =#
if endswith(f.name, "/")
continue
end
Expand All @@ -35,24 +35,79 @@ function downloadAndExtractLibraries(libraryString; URL)
write(outPath, read(f))
end
close(r)

#= Clean up the zip file =#
rm(zipPath)

@info "Successfully extracted libraries to $(sharedDir)/$(libraryString)/"
end

function downloadCallbacksShim(libSubdir::String)
local url = "$(CALLBACKS_BASE_URL)/$(libSubdir)-callbacks.tar.gz"
local outDir = joinpath(PATH_TO_EXT, "shared", libSubdir)
mkpath(outDir)

local ext = Sys.iswindows() ? ".dll" : Sys.isapple() ? ".dylib" : ".so"
local outFile = joinpath(outDir, "libModelicaCallbacks$ext")
if isfile(outFile)
@info "ModelicaCallbacks shim already exists at $outFile"
return
end

@info "Downloading ModelicaCallbacks shim from $(url)..."
try
local tgzPath = joinpath(PATH_TO_EXT, "$(libSubdir)-callbacks.tar.gz")
HTTP.download(url, tgzPath)
open(tgzPath) do io
Tar.extract(Inflate.inflate_gzip(io), outDir)
end
rm(tgzPath)
@info "Successfully installed ModelicaCallbacks shim to $outDir"
catch e
@warn "Failed to download pre-built ModelicaCallbacks shim: $e"
@info "Attempting to compile from source..."
buildModelicaCallbacksFromSource(libSubdir)
end
end

function buildModelicaCallbacksFromSource(libSubdir::String)
local srcFile = joinpath(PACKAGE_DIR, "src", "modelica_callbacks.c")
local outDir = joinpath(PATH_TO_EXT, "shared", libSubdir)
mkpath(outDir)

local ext, compileCmd
if Sys.islinux()
ext = ".so"
compileCmd = `gcc -shared -fPIC -o $(joinpath(outDir, "libModelicaCallbacks$ext")) $srcFile -ldl`
elseif Sys.isapple()
ext = ".dylib"
compileCmd = `cc -dynamiclib -fPIC -o $(joinpath(outDir, "libModelicaCallbacks$ext")) $srcFile -ldl`
elseif Sys.iswindows()
ext = ".dll"
compileCmd = `gcc -shared -o $(joinpath(outDir, "libModelicaCallbacks$ext")) $srcFile`
else
@warn "Cannot build ModelicaCallbacks: unsupported platform"
return
end

try
run(compileCmd)
@info "Successfully compiled ModelicaCallbacks shim"
catch e
@warn "Failed to compile ModelicaCallbacks shim: $e"
end
end

@static if Sys.iswindows()
downloadAndExtractLibraries("x86_64-mingw32";
URL="$(RELEASE_BASE_URL)/x86_64-mingw32.zip")
downloadCallbacksShim("x86_64-mingw32")
elseif Sys.islinux()
downloadAndExtractLibraries("x86_64-linux-gnu";
URL="$(RELEASE_BASE_URL)/x86_64-linux-gnu.zip")
downloadCallbacksShim("x86_64-linux-gnu")
elseif Sys.isapple()
@warn "macOS is currently not supported due to dylib path issues in the OpenModelica build system."
@warn "See: https://trac.openmodelica.org/OpenModelica/ticket/4647"
@warn "Some functionality requiring external C libraries will not be available."
@warn "macOS: Modelica external C libraries are not yet available."
local arch = Sys.ARCH == :aarch64 ? "aarch64-apple-darwin" : "x86_64-apple-darwin"
downloadCallbacksShim(arch)
else
@warn "This platform is not supported."
@warn "Some functionality requiring external C libraries will not be available."
end
13 changes: 13 additions & 0 deletions src/OMRuntimeExternalC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,19 @@ function __init__()
ENV["LD_LIBRARY_PATH"] = isempty(ldpath) ? libdir : libdir * ":" * ldpath
end
end
#= Load the Julia-compatible ModelicaCallbacks shim FIRST with RTLD_GLOBAL
so it overrides the OMC setjmp/longjmp-based error handlers.
Then load the other libraries with RTLD_GLOBAL so their symbols are
visible to dlsym (used by the safe_* wrappers in the callbacks shim). =#
if installedLibPathlibModelicaCallbacks !== nothing
Libdl.dlopen(installedLibPathlibModelicaCallbacks, Libdl.RTLD_GLOBAL)
end
if installedLibPathlibModelicaIO !== nothing
Libdl.dlopen(installedLibPathlibModelicaIO, Libdl.RTLD_GLOBAL)
end
if installedLibPathlibModelicaExternalC !== nothing
Libdl.dlopen(installedLibPathlibModelicaExternalC, Libdl.RTLD_GLOBAL)
end
catch
@warn "Failed to setup the environment correctly. Make sure that you have the correct shared libraries installed."
@warn "NOTE: If your Modelica model uses certain external functions your simulation might fail."
Expand Down
Loading
Loading