Skip to content

Make universal mac builds for FMI<=2 #639

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ jobs:
- name: x86_64-darwin
image: macos-13
arch: x86_64
- name: universal64-darwin
image: macos-13
arch: x86_64
- name: aarch64-darwin
image: macos-13
arch: aarch64
Expand Down Expand Up @@ -91,6 +94,10 @@ jobs:
with:
name: x86_64-darwin
path: dist-x86_64-darwin
- uses: actions/download-artifact@v4
with:
name: universal64-darwin
path: dist-universal64-darwin
- uses: actions/download-artifact@v4
with:
name: aarch64-darwin
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ else ()

if ("${FMI_ARCHITECTURE}" STREQUAL "x86_64")
set (FMI_PLATFORM ${FMI_PLATFORM}64)
elseif ("${FMI_ARCHITECTURE}" STREQUAL "universal64")
set (FMI_PLATFORM ${FMI_PLATFORM}64)
elseif ("${FMI_ARCHITECTURE}" STREQUAL "x86")
set (FMI_PLATFORM ${FMI_PLATFORM}32)
else ()
Expand All @@ -85,6 +87,8 @@ if (APPLE)
set(CMAKE_OSX_ARCHITECTURES "x86_64")
elseif ("${FMI_ARCHITECTURE}" STREQUAL "aarch64")
set(CMAKE_OSX_ARCHITECTURES "arm64")
elseif ("${FMI_ARCHITECTURE}" STREQUAL "universal64")
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
else ()
message(FATAL_ERROR "Unsupported architecture darwin: ${FMI_ARCHITECTURE}")
endif ()
Expand Down
11 changes: 7 additions & 4 deletions build/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
parser = argparse.ArgumentParser()
parser.add_argument(
'platform',
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin'},
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin', 'universal64-darwin'},
help="Platform to build for, e.g. x86_64-windows"
)
parser.add_argument(
Expand Down Expand Up @@ -91,6 +91,9 @@ def build_fmus(fmi_version, fmi_type=None):

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64']

elif fmi_platform == 'universal64-darwin':
cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64']

install_dir = build_dir / 'install'

if fmi_type is not None:
Expand Down Expand Up @@ -135,9 +138,9 @@ def build_fmus(fmi_version, fmi_type=None):

if __name__ == '__main__':

if args.platform in {'x86_64-linux', 'x86-windows', 'x86_64-windows', 'x86_64-darwin'}:
if args.platform in {'x86_64-linux', 'x86-windows', 'x86_64-windows', 'x86_64-darwin', 'universal64-darwin'}:
build_fmus(fmi_version=1, fmi_type='me')
build_fmus(fmi_version=1, fmi_type='cs')
build_fmus(fmi_version=2)

build_fmus(fmi_version=3)
if args.platform not in {'universal64-darwin'}:
build_fmus(fmi_version=3)
6 changes: 5 additions & 1 deletion build/build_cvode.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
parser = argparse.ArgumentParser()
parser.add_argument(
'platform',
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin'},
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin', 'universal64-darwin'},
help="Platform to build for, e.g. x86_64-windows"
)
parser.add_argument(
Expand Down Expand Up @@ -62,6 +62,10 @@

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64']

elif fmi_platform == 'universal64-darwin':

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64']

check_call(
['cmake'] +
cmake_args +
Expand Down
6 changes: 5 additions & 1 deletion build/build_libxml2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
parser = argparse.ArgumentParser()
parser.add_argument(
'platform',
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin'},
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin', 'universal64-darwin'},
help="Platform to build for, e.g. x86_64-windows"
)
parser.add_argument(
Expand Down Expand Up @@ -60,6 +60,10 @@

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64']

elif fmi_platform == 'universal64-darwin':

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64']

check_call(
['cmake'] +
cmake_args +
Expand Down
6 changes: 5 additions & 1 deletion build/build_zlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
parser = argparse.ArgumentParser()
parser.add_argument(
'platform',
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin'},
choices={'x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin', 'universal64-darwin'},
help="Platform to build for, e.g. x86_64-windows"
)
parser.add_argument(
Expand Down Expand Up @@ -63,6 +63,10 @@

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64']

elif fmi_platform == 'universal64-darwin':

cmake_args += ['-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64']

check_call(
['cmake'] +
cmake_args +
Expand Down
8 changes: 4 additions & 4 deletions build/merge_binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ def merge_fmus(version):

tempdir = Path(mkdtemp())

platforms = ['x86-windows', 'x86_64-windows', 'x86_64-linux', 'x86_64-darwin']

if version == '3.0':
platforms += ['aarch64-linux', 'aarch64-darwin']
platforms = ['x86-windows', 'x86_64-windows', 'x86_64-linux', 'x86_64-darwin', 'aarch64-linux', 'aarch64-darwin']
else:
platforms = ['x86-windows', 'x86_64-windows', 'x86_64-linux', 'universal64-darwin']

for platform in platforms:

Expand Down Expand Up @@ -179,7 +179,7 @@ def get_unit(variable):
os.makedirs(results_dir, exist_ok=True)

# copy fmusim
for system in ['x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin']:
for system in ['x86-windows', 'x86_64-windows', 'x86_64-linux', 'aarch64-linux', 'x86_64-darwin', 'aarch64-darwin', 'universal64-darwin']:
shutil.copytree(src=root / f'dist-{system}' / f'fmusim-{system}', dst=root / 'dist-merged' / f'fmusim-{system}')

# copy license and readme
Expand Down
58 changes: 41 additions & 17 deletions tests/test_fmusim.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ def call_fmusim(platform: str, fmi_version: int, interface_type: str, test_name:
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_start_time(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result = call_fmusim(platform, fmi_version, interface_type, 'test_start_time', ['--start-time', '0.5'])
Expand All @@ -55,7 +56,8 @@ def test_start_time(fmi_version, interface_type, arch, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_stop_time(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result = call_fmusim(platform, fmi_version, interface_type, 'test_stop_time', ['--stop-time', '1.5'])
Expand All @@ -66,7 +68,8 @@ def test_stop_time(fmi_version, interface_type, arch, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_set_stop_time(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result = call_fmusim(platform, fmi_version, interface_type, 'test_set_stop_time',
Expand All @@ -83,7 +86,8 @@ def test_set_stop_time(fmi_version, interface_type, arch, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_start_value_types(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

args = [
Expand Down Expand Up @@ -134,7 +138,9 @@ def test_start_value_types(fmi_version, interface_type, arch, platform):


@pytest.mark.parametrize('interface_type', ['cs', 'me'])
def test_start_value_arrays(work_dir, interface_type, platform):
def test_start_value_arrays(work_dir, interface_type, arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

call_fmusim(
platform=platform,
Expand Down Expand Up @@ -164,7 +170,8 @@ def test_start_value_arrays(work_dir, interface_type, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_input_file(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result = call_fmusim(
Expand Down Expand Up @@ -197,7 +204,9 @@ def test_input_file(fmi_version, interface_type, arch, platform):
assert result['Int32_output'][-1] == 2


def test_arrays(work_dir, platform):
def test_arrays(work_dir, arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

call_fmusim(
platform=platform,
Expand Down Expand Up @@ -227,7 +236,9 @@ def test_arrays(work_dir, platform):
'''


def test_collapsed_array(work_dir, platform):
def test_collapsed_array(work_dir, arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

call_fmusim(
platform=platform,
Expand Down Expand Up @@ -258,7 +269,8 @@ def test_collapsed_array(work_dir, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_fmi_log_file(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

fmi_log_file = work / f'test_fmi_log_file_fmi{fmi_version}_{interface_type}.txt'
Expand All @@ -277,7 +289,8 @@ def test_fmi_log_file(fmi_version, interface_type, arch, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_output_interval(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result = call_fmusim(
Expand All @@ -297,7 +310,8 @@ def test_output_interval(fmi_version, interface_type, arch, platform):
@pytest.mark.parametrize('fmi_version, solver', product([1, 2, 3], ['euler', 'cvode']))
def test_solver(fmi_version, solver, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

call_fmusim(
Expand All @@ -312,7 +326,8 @@ def test_solver(fmi_version, solver, arch, platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([1, 2, 3], ['cs', 'me']))
def test_output_variable(fmi_version, interface_type, arch, platform):

if fmi_version in {1, 2} and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result = call_fmusim(
Expand All @@ -326,7 +341,9 @@ def test_output_variable(fmi_version, interface_type, arch, platform):
assert set(result.dtype.names) == {'time', 'e', 'der(h)'}


def test_intermediate_values(platform):
def test_intermediate_values(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

result = call_fmusim(
platform=platform,
Expand All @@ -339,7 +356,9 @@ def test_intermediate_values(platform):
assert np.all(np.diff(result['time']) < 0.1)


def test_early_return_state_events(platform):
def test_early_return_state_events(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

result = call_fmusim(
platform=platform,
Expand All @@ -354,7 +373,9 @@ def test_early_return_state_events(platform):
assert np.sum(np.logical_and(time > 0, time < 0.5)) == 1


def test_event_mode_input_events(platform):
def test_event_mode_input_events(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

input_file = resources / 'Feedthrough_in.csv'

Expand All @@ -378,7 +399,9 @@ def test_event_mode_input_events(platform):
assert np.all(result['Int32_output'] == [1, 1, 1, 1, 1, 1, 1, 2, 2])


def test_event_mode_time_events(platform):
def test_event_mode_time_events(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

result = call_fmusim(
platform=platform,
Expand All @@ -401,7 +424,8 @@ def test_event_mode_time_events(platform):
@pytest.mark.parametrize('fmi_version, interface_type', product([2, 3], ['cs', 'me']))
def test_restore_fmu_state(fmi_version, interface_type, arch, platform):

if fmi_version == 2 and arch not in {'x86', 'x86_64'}:
if (fmi_version in {1, 2} and arch not in {'x86', 'x86_64', 'universal64'}) or \
(fmi_version in {3} and arch in {'universal64'}):
pytest.skip(f"FMI version {fmi_version} is not supported on {arch}.")

result1 = call_fmusim(
Expand Down
23 changes: 17 additions & 6 deletions tests/test_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def validate(build_dir, model, fmi_types, simulate=True):

def test_fmi1_me(arch, platform):

if arch not in {'x86', 'x86_64'}:
if arch not in {'x86', 'x86_64', 'universal64'}:
pytest.skip(f"{arch} not supported")

build_dir = root / 'build' / f'fmi1-me-{platform}'
Expand All @@ -59,7 +59,7 @@ def test_fmi1_me(arch, platform):

def test_fmi1_cs(arch, platform):

if arch not in {'x86', 'x86_64'}:
if arch not in {'x86', 'x86_64', 'universal'}:
pytest.skip(f"{arch} not supported")

build_dir = root / 'build' / f'fmi1-cs-{platform}'
Expand All @@ -75,7 +75,7 @@ def test_fmi1_cs(arch, platform):

def test_fmi2(arch, platform):

if arch not in {'x86', 'x86_64'}:
if arch not in {'x86', 'x86_64', 'universal64'}:
pytest.skip(f"{arch} not supported")

build_dir = root / 'build' / f'fmi2-{platform}'
Expand All @@ -93,6 +93,9 @@ def test_fmi2(arch, platform):

def test_fmi3(arch, platform):

if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

build_dir = root / 'build' / f'fmi3-{platform}'

models = ['BouncingBall', 'Dahlquist', 'Feedthrough', 'Resource', 'Stair', 'StateSpace', 'VanDerPol']
Expand All @@ -108,15 +111,23 @@ def test_fmi3(arch, platform):
assert not validate_fmu(build_dir / 'install' / 'Clocks.fmu')


def test_cs_early_return(platform):
def test_cs_early_return(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

run_example(root / 'build' / f'fmi3-{platform}' / 'temp' / 'cs_early_return')


def test_cs_event_mode(platform):
def test_cs_event_mode(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

run_example(root / 'build' / f'fmi3-{platform}' / 'temp' / 'cs_event_mode')


def test_cs_reconfiguration(platform):
def test_cs_reconfiguration(arch, platform):
if arch in {'universal64'}:
pytest.skip(f"FMI version 3 is not supported on {arch}.")

build_dir = root / 'build' / f'fmi3-{platform}' / 'temp'

Expand Down
Loading