Skip to content

Commit 8075ea4

Browse files
authored
Added ARM support on Windows and Linux.
2 parents ccce4c8 + f78081f commit 8075ea4

24 files changed

+604
-795
lines changed

.github/workflows/cd.yml

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
name: CD
22

33
on:
4-
push:
54
release:
65
types: [created]
76
workflow_dispatch:
@@ -14,14 +13,19 @@ jobs:
1413
fail-fast: false
1514
matrix:
1615
include:
17-
- name: Windows
18-
os: windows-latest
19-
- name: Linux
20-
os: ubuntu-latest
16+
- name: Windows (Intel)
17+
os: windows-2022
18+
#---OPENCOR--- The below is to be enabled once GitHub Actions has Windows ARM runners.
19+
# - name: Windows (ARM)
20+
# os: windows-2019
21+
- name: Linux (Intel)
22+
os: ubuntu-22.04
23+
- name: Linux (ARM)
24+
os: ubuntu-22.04-arm
2125
- name: macOS (Intel)
2226
os: macos-13
2327
- name: macOS (ARM)
24-
os: macos-latest
28+
os: macos-14
2529
env:
2630
APPLE_ID: ${{ secrets.APPLE_ID }}
2731
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
@@ -42,14 +46,14 @@ jobs:
4246
- name: Check out OpenCOR
4347
uses: actions/checkout@v4
4448
- name: Retrieve the EV certificate (Windows only)
45-
if: matrix.name == 'Windows'
49+
if: ${{ (matrix.name == 'Windows (Intel)') || (matrix.name == 'Windows (ARM)') }}
4650
shell: bash
4751
run: |
4852
echo "CSC_LINK=$(echo $WINDOWS_CSC_LINK)" >> $GITHUB_ENV
4953
echo "CSC_KEY_PASSWORD=$(echo $WINDOWS_CSC_KEY_PASSWORD)" >> $GITHUB_ENV
5054
echo -n $EV_CERTIFICATE_BASE64 | base64 -d > $WINDOWS_CSC_LINK
5155
- name: Retrieve the Developer ID Application certificates (macOS only)
52-
if: matrix.name == 'macOS (Intel)' || matrix.name == 'macOS (ARM)'
56+
if: ${{ (matrix.name == 'macOS (Intel)') || (matrix.name == 'macOS (ARM)') }}
5357
run: |
5458
echo "CSC_LINK=$(echo $MACOS_CSC_LINK)" >> $GITHUB_ENV
5559
echo "CSC_KEY_PASSWORD=$(echo $MACOS_CSC_KEY_PASSWORD)" >> $GITHUB_ENV
@@ -60,10 +64,15 @@ jobs:
6064
node-version: 'lts/*'
6165
- name: Install pnpm
6266
run: npm install -g pnpm
63-
- name: Package OpenCOR
67+
- name: Install libopenjp2-tools (Linux ARM only)
68+
if: matrix.name == 'Linux (ARM)'
6469
run: |
65-
pnpm install
66-
pnpm package
70+
sudo apt update
71+
sudo apt install libopenjp2-tools
72+
- name: OpenCOR dependencies
73+
run: pnpm install
74+
- name: Package OpenCOR
75+
run: pnpm package
6776
- name: Remove blockmap files
6877
shell: bash
6978
run: find ./dist -name '*.blockmap' -delete

.github/workflows/ci.yml

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,28 @@ jobs:
1313
fail-fast: false
1414
matrix:
1515
include:
16-
- name: Windows
17-
os: windows-latest
18-
build: ON
19-
- name: Linux
20-
os: ubuntu-latest
21-
build: ON
16+
- name: Windows (Intel)
17+
os: windows-2022
18+
#---OPENCOR--- The below is to be enabled once GitHub Actions has Windows ARM runners.
19+
# - name: Windows (ARM)
20+
# os: windows-2019
21+
- name: Linux (Intel)
22+
os: ubuntu-22.04
23+
- name: Linux (ARM)
24+
os: ubuntu-22.04-arm
2225
- name: macOS (Intel)
2326
os: macos-13
24-
build: ON
2527
- name: macOS (ARM)
26-
os: macos-latest
27-
build: ON
28+
os: macos-14
2829
- name: Code formatting
29-
os: ubuntu-latest
30-
build: OFF
30+
os: ubuntu-22.04
3131
- name: Linting
32-
os: ubuntu-latest
33-
build: OFF
32+
os: ubuntu-22.04
3433
steps:
3534
- name: Check out OpenCOR
3635
uses: actions/checkout@v4
36+
- name: Install CMake and Ninja
37+
uses: lukka/get-cmake@latest
3738
- name: Install Node.js
3839
uses: actions/setup-node@v4
3940
with:
@@ -43,10 +44,10 @@ jobs:
4344
- name: OpenCOR dependencies
4445
run: pnpm install
4546
- name: Build OpenCOR
46-
if: matrix.build == 'ON'
47+
if: ${{ (matrix.name != 'Code formatting') && (matrix.name != 'Linting') }}
4748
run: pnpm build
4849
- name: Build OpenCOR's Web app
49-
if: matrix.build == 'ON'
50+
if: ${{ (matrix.name != 'Code formatting') && (matrix.name != 'Linting') }}
5051
run: pnpm build:web
5152
- name: Code formatting
5253
if: matrix.name == 'Code formatting'

.npmrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
electron_mirror=https://npmmirror.com/mirrors/electron/
22
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
3+
node-linker=hoisted
4+
public-hoist-pattern=*

CMakeLists.txt

Lines changed: 68 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
cmake_minimum_required(VERSION 3.15)
22

3-
project(libOpenCOR
4-
VERSION 0.0.0)
3+
project(libOpenCOR VERSION 0.0.0)
54

65
# Enable C++20.
76

87
set(CMAKE_CXX_STANDARD 20)
98
set(CMAKE_CXX_STANDARD_REQUIRED ON)
109
set(CMAKE_CXX_EXTENSIONS OFF)
1110

11+
# Some common CMake policies.
12+
13+
foreach(POLICY CMP0042 CMP0091)
14+
cmake_policy(SET ${POLICY} NEW)
15+
endforeach()
16+
1217
# Get access to cmake-js.
1318

1419
include_directories(${CMAKE_JS_INC})
@@ -17,24 +22,30 @@ include_directories(${CMAKE_JS_INC})
1722

1823
if(WIN32)
1924
set(PLATFORM Windows)
20-
set(ARCHITECTURE Intel)
2125
set(EXTENSION .zip)
2226
elseif(APPLE)
2327
set(PLATFORM macOS)
2428
set(EXTENSION .zip)
29+
else()
30+
set(PLATFORM Linux)
31+
set(EXTENSION .tar.gz)
32+
endif()
2533

26-
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
34+
if(WIN32)
35+
if("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "x64")
2736
set(ARCHITECTURE Intel)
2837
else()
2938
set(ARCHITECTURE ARM)
3039
endif()
3140
else()
32-
set(PLATFORM Linux)
33-
set(ARCHITECTURE Intel)
34-
set(EXTENSION .tar.gz)
41+
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
42+
set(ARCHITECTURE Intel)
43+
else()
44+
set(ARCHITECTURE ARM)
45+
endif()
3546
endif()
3647

37-
set(LIBOPENCOR_FILE_NAME_WE libOpenCOR-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-${PLATFORM}-${ARCHITECTURE}-Shared)
48+
set(LIBOPENCOR_FILE_NAME_WE ${CMAKE_PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-${PLATFORM}-${ARCHITECTURE}-Shared)
3849
set(LIBOPENCOR_FILE_NAME ${LIBOPENCOR_FILE_NAME_WE}${EXTENSION})
3950

4051
file(DOWNLOAD https://opencor.ws/libopencor/downloads/${LIBOPENCOR_FILE_NAME}
@@ -44,10 +55,14 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ${CMAKE_BINARY_DIR}/${LIBOPE
4455
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
4556
OUTPUT_QUIET)
4657

58+
execute_process(COMMAND ${CMAKE_COMMAND} -E rename ${LIBOPENCOR_FILE_NAME_WE} Shared
59+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
60+
OUTPUT_QUIET)
61+
4762
file(REMOVE ${CMAKE_BINARY_DIR}/${LIBOPENCOR_FILE_NAME})
4863

49-
include_directories(${CMAKE_BINARY_DIR}/${LIBOPENCOR_FILE_NAME_WE}/include
50-
${CMAKE_BINARY_DIR}/${LIBOPENCOR_FILE_NAME_WE}/include/libopencor/module)
64+
include_directories(${CMAKE_BINARY_DIR}/Shared/include
65+
${CMAKE_BINARY_DIR}/Shared/include/libopencor/module)
5166

5267
# Use the appropriate C runtime library.
5368

@@ -106,42 +121,70 @@ set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES
106121
PREFIX ""
107122
SUFFIX ".node")
108123

124+
# Generate node.lib.
125+
126+
if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)
127+
execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS})
128+
endif()
129+
109130
# Link cmake-js and libOpenCOR to our Node.js add-on.
110131

111132
if(WIN32)
112-
set(LIBOPENCOR_FILENAME libOpenCOR${CMAKE_IMPORT_LIBRARY_SUFFIX})
133+
set(LIBOPENCOR_DIR bin)
134+
set(FULL_LIBOPENCOR_FILENAME ${CMAKE_PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX})
135+
else()
136+
set(LIBOPENCOR_DIR lib)
137+
138+
if(APPLE)
139+
set(FULL_LIBOPENCOR_FILENAME ${CMAKE_PROJECT_NAME}.${CMAKE_PROJECT_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX})
140+
else()
141+
set(FULL_LIBOPENCOR_FILENAME ${CMAKE_PROJECT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX}.${CMAKE_PROJECT_VERSION})
142+
endif()
143+
endif()
144+
145+
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/Shared/${LIBOPENCOR_DIR}/${FULL_LIBOPENCOR_FILENAME}
146+
${CMAKE_BINARY_DIR}/../${FULL_LIBOPENCOR_FILENAME})
147+
148+
if(WIN32)
149+
set(LIBOPENCOR_FILENAME ${CMAKE_PROJECT_NAME}${CMAKE_IMPORT_LIBRARY_SUFFIX})
150+
151+
execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/Shared/lib/${LIBOPENCOR_FILENAME}
152+
${CMAKE_BINARY_DIR}/../${LIBOPENCOR_FILENAME})
113153
else()
114-
set(LIBOPENCOR_FILENAME libOpenCOR${CMAKE_SHARED_LIBRARY_SUFFIX})
154+
set(LIBOPENCOR_FILENAME ${FULL_LIBOPENCOR_FILENAME})
115155
endif()
116156

117157
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
118158
${CMAKE_JS_LIB}
119-
${CMAKE_BINARY_DIR}/${LIBOPENCOR_FILE_NAME_WE}/lib/${LIBOPENCOR_FILENAME})
159+
${CMAKE_BINARY_DIR}/../${LIBOPENCOR_FILENAME})
120160

121-
# Include the Node-API wrappers.
161+
set(LIBOPENCOR_NODE_FILENAME ${CMAKE_BINARY_DIR}/../${CMAKE_PROJECT_NAME}.node)
122162

123-
execute_process(COMMAND node -p "require('node-addon-api').include"
124-
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
125-
OUTPUT_VARIABLE NODE_ADDON_API_DIR)
163+
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
164+
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${CMAKE_PROJECT_NAME}>
165+
${LIBOPENCOR_NODE_FILENAME})
126166

127-
string(REGEX REPLACE "[\r\n\"]" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
167+
# On Linux, replace the RUNPATH value with an RPATH value of $ORIGIN so that, once deployed, OpenCOR can find our C++
168+
# version of libOpenCOR.
128169

129-
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
130-
${NODE_ADDON_API_DIR})
170+
if(NOT WIN32 AND NOT APPLE)
171+
find_program(PATCHELF patchelf REQUIRED)
131172

132-
add_definitions(-DNAPI_VERSION=3)
173+
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
174+
COMMAND ${PATCHELF} --set-rpath "\\$$ORIGIN" --force-rpath ${LIBOPENCOR_NODE_FILENAME})
175+
endif()
133176

134177
# Configure our splash screen.
135178

136179
string(TIMESTAMP CURRENT_YEAR "%Y")
137180

138-
if(CURRENT_YEAR EQUAL 2024)
139-
set(COPYRIGHT "2024")
181+
if(CURRENT_YEAR EQUAL 2025)
182+
set(COPYRIGHT "2025")
140183
else()
141-
set(COPYRIGHT "2024-${CURRENT_YEAR}")
184+
set(COPYRIGHT "2025-${CURRENT_YEAR}")
142185
endif()
143186

144187
set(VERSION ${PROJECT_VERSION})
145188

146189
configure_file(src/main/assets/splashscreen.html.in
147-
${CMAKE_BINARY_DIR}/splashscreen.html)
190+
${CMAKE_BINARY_DIR}/../splashscreen.html)

README.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,36 @@
44

55
There are two versions of OpenCOR:
66

7-
1. **OpenCOR:** a desktop application that can be run on [Windows](https://en.wikipedia.org/wiki/Microsoft_Windows), [Linux](https://en.wikipedia.org/wiki/Linux), and [macOS](https://en.wikipedia.org/wiki/MacOS); and
7+
1. **OpenCOR:** a desktop application that can be run on [Windows](https://en.wikipedia.org/wiki/Microsoft_Windows), [Linux](https://en.wikipedia.org/wiki/Linux), and [macOS](https://en.wikipedia.org/wiki/MacOS) on [Intel](https://en.wikipedia.org/wiki/List_of_Intel_processors)/[ARM](https://en.wikipedia.org/wiki/ARM_architecture_family); and
88
2. **OpenCOR's Web app:** a [Web app](https://en.wikipedia.org/wiki/Web_application) that can be run using a Web browser.
99

1010
The main difference between the two versions is that models in OpenCOR are, by default, compiled while they can only be interpreted in OpenCOR's Web app.
1111

1212
## Prerequisites
1313

14-
To build OpenCOR, you need to install [node.js](https://nodejs.org/) and [npm](https://npmjs.com/), which you can do from [here](https://nodejs.org/en/download/package-manager). Then, you need to install [pnpm](https://pnpm.io/):
14+
To build OpenCOR and OpenCOR's Web app, you need to install [node.js](https://nodejs.org/) and [npm](https://npmjs.com/), which you can do from [here](https://nodejs.org/en/download/package-manager). Then, you need to install [pnpm](https://pnpm.io/):
1515

1616
```bash
17-
npm install -g pnpm
17+
npm -g install pnpm
1818
```
1919

20+
To build OpenCOR, you also need a C/C++ toolchain:
21+
22+
- **[Windows](https://en.wikipedia.org/wiki/Microsoft_Windows):**
23+
- **[Intel](https://en.wikipedia.org/wiki/List_of_Intel_processors):**
24+
- [Visual Studio Community 2019](https://apps.microsoft.com/detail/xp8cdjnzkfm06w) (`Desktop development with C++` with `MSVC v142 - VS 2019 C++ x64/x86 build tools` and `Windows 10 SDK`); or
25+
- [Visual Studio Community 2022](https://apps.microsoft.com/detail/xpdcfjdklzjlp8) (`Desktop development with C++` with `MSVC v143 - VS 2022 C++ x64/x86 build tools` and `Windows 11 SDK`);
26+
- **[ARM](https://en.wikipedia.org/wiki/ARM_architecture_family):**
27+
- [Visual Studio Community 2019](https://apps.microsoft.com/detail/xp8cdjnzkfm06w) (`Desktop development with C++` with `MSVC v142 - VS 2019 C++ ARM64 build tools` and `Windows 10 SDK`);
28+
- **[Linux](https://en.wikipedia.org/wiki/Linux):** G++ (`g++` package) on [Ubuntu 22.04 LTS](https://en.wikipedia.org/wiki/Ubuntu_version_history#2204)/[Ubuntu 24.04 LTS](https://en.wikipedia.org/wiki/Ubuntu_version_history#2404); and
29+
- **[macOS](https://en.wikipedia.org/wiki/MacOS):** [Xcode](https://developer.apple.com/xcode/) (including its [Command Line Tools](https://developer.apple.com/downloads/?q=Command%20Line%20Tools)).
30+
31+
**Notes:**
32+
33+
- Yes, OpenCOR for [Windows](https://en.wikipedia.org/wiki/Microsoft_Windows) on [ARM](https://en.wikipedia.org/wiki/ARM_architecture_family) can only be built using [Visual Studio Community 2019](https://apps.microsoft.com/detail/xp8cdjnzkfm06w) (this is because we must use `MSVC v142`; see [here](https://www.electronjs.org/docs/latest/tutorial/windows-arm#native-modules) for more information).
34+
- On Ubuntu on ARM, you need to install the `libopenjp2-tools` package so that [`electron-builder`](https://www.electron.build/) can get access to [`opj_decompress`](https://manpages.ubuntu.com/manpages/man1/opj_decompress.1.html).
35+
- On [Ubuntu 24.04 LTS](https://en.wikipedia.org/wiki/Ubuntu_version_history#2404), you need to deactivate restrictions using `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0` (see [here](https://github.com/electron/electron/issues/42510) for more information).
36+
2037
## Scripts
2138

2239
Before doing anything, you need to install all of OpenCOR's dependencies:
@@ -43,9 +60,6 @@ where `<script>` is one of the following:
4360
- `format:check`: check that OpenCOR's code and OpenCOR's Web app's code are properly formatted;
4461
- `lint`: lint OpenCOR's code and OpenCOR's Web app's code;
4562
- `package`: (build and) package OpenCOR for the current platform;
46-
- `package:linux`: (build and) package OpenCOR for Linux;
47-
- `package:mac`: (build and) package OpenCOR for macOS;
48-
- `package:win`: (build and) package OpenCOR for Windows;
4963
- `publish:web`: publish OpenCOR's Web app on [npm](https://npmjs.com/);
5064
- `start`: start OpenCOR in production mode; and
5165
- `start:web`: start OpenCOR's Web app in production mode.

electron-builder.yml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ productName: OpenCOR
33
win:
44
artifactName: ${productName}-${version}-Windows.${ext}
55
extraFiles:
6-
- from: 'out/libOpenCOR/libOpenCOR-0.0.0-Windows-Intel-Shared/bin/libOpenCOR.dll'
6+
- from: 'out/libOpenCOR.dll'
77
to: 'libOpenCOR.dll'
88
target:
99
- nsis
@@ -15,11 +15,10 @@ linux:
1515
category: Utility
1616
executableName: OpenCOR
1717
extraFiles:
18-
- from: 'out/libOpenCOR/libOpenCOR-0.0.0-Linux-Intel-Shared/lib/libOpenCOR.so.0.0.0'
18+
- from: 'out/libOpenCOR.so.0.0.0'
1919
to: 'libOpenCOR.so.0.0.0'
2020
target:
2121
- AppImage
22-
- deb
2322
- tar.gz
2423
mac:
2524
# - Code signing:
@@ -33,9 +32,7 @@ mac:
3332
# - APPLE_TEAM_ID: an id that can be found in the top right corner of https://developer.apple.com/account/resources/certificates/list.
3433
artifactName: ${productName}-${version}-macOS-${arch}.${ext}
3534
extraFiles:
36-
- from: 'out/libOpenCOR/libOpenCOR-0.0.0-macOS-Intel-Shared/lib/libOpenCOR.0.0.0.dylib'
37-
to: 'Frameworks/libOpenCOR.0.0.0.dylib'
38-
- from: 'out/libOpenCOR/libOpenCOR-0.0.0-macOS-ARM-Shared/lib/libOpenCOR.0.0.0.dylib'
35+
- from: 'out/libOpenCOR.0.0.0.dylib'
3936
to: 'Frameworks/libOpenCOR.0.0.0.dylib'
4037
target:
4138
- dmg

electron.vite.config.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,7 @@ export default defineConfig({
2525
viteStaticCopy({
2626
targets: [
2727
{
28-
src: normalizePath(
29-
path.resolve(
30-
import.meta.dirname,
31-
'out/libOpenCOR/libOpenCOR-0.0.0-Windows-Intel-Shared/bin/libOpenCOR.dll'
32-
)
33-
),
28+
src: normalizePath(path.resolve(import.meta.dirname, 'out/libOpenCOR.dll')),
3429
dest: 'chunks'
3530
}
3631
]

0 commit comments

Comments
 (0)