From 526ecd7670423e29e06ea7f1b0eb02c571057942 Mon Sep 17 00:00:00 2001 From: Alan Garny Date: Wed, 17 Jun 2026 23:47:15 +1200 Subject: [PATCH 1/4] New version. --- VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION.txt b/VERSION.txt index 0e508116e..0db057113 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.20260616.0 +0.20260618.0 From 773b950d84fd43afd71f9a3d0baaa7ca8cbc850a Mon Sep 17 00:00:00 2001 From: Alan Garny Date: Thu, 18 Jun 2026 16:26:53 +1200 Subject: [PATCH 2/4] CMake: some minor cleaning up. --- cmake/clcachewrapper.c | 2 +- cmake/formatting/CMakeLists.txt | 2 ++ src/CMakeLists.txt | 10 +++++++++- tests/CMakeLists.txt | 9 +++++++-- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/cmake/clcachewrapper.c b/cmake/clcachewrapper.c index 78b54ee61..a2c55aa10 100644 --- a/cmake/clcachewrapper.c +++ b/cmake/clcachewrapper.c @@ -21,7 +21,7 @@ int main(int pArgC, char *pArgV[]) { // Call clcache with the given arguments, except the first one, which is the full path to the MSVC compiler. - #define STRING_SIZE 32768 +#define STRING_SIZE 32768 char clcacheCommand[STRING_SIZE] = "clcache"; int k = 6; diff --git a/cmake/formatting/CMakeLists.txt b/cmake/formatting/CMakeLists.txt index bf8d1fc12..0cdb00cd2 100644 --- a/cmake/formatting/CMakeLists.txt +++ b/cmake/formatting/CMakeLists.txt @@ -17,6 +17,8 @@ if(FORMAT_CODE_AVAILABLE) set(GIT_FILES + ${CMAKE_SOURCE_DIR}/cmake/base64encoder.cpp + ${CMAKE_SOURCE_DIR}/cmake/clcachewrapper.c ${GIT_API_HEADER_FILES} ${GIT_API_MODULE_FILE} ${GIT_SOURCE_FILES} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e53e2cc43..63a77d6db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,12 +21,20 @@ if(LIBOPENCOR_COMPILER_CACHING) elseif(CLCACHE_EXE) set(CLCACHEWRAPPER ${CMAKE_BINARY_DIR}/clcachewrapper) - try_compile(CLCACHEWRAPPER_EXE ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/cmake/clcachewrapper.c + message(STATUS "Building clcachewrapper") + + try_compile(CLCACHEWRAPPER_EXE ${CMAKE_BINARY_DIR} + SOURCES ${CMAKE_SOURCE_DIR}/cmake/clcachewrapper.c COPY_FILE ${CLCACHEWRAPPER}) if(CLCACHEWRAPPER_EXE) + message(STATUS "Building clcachewrapper - Success") + set(CMAKE_C_COMPILER_LAUNCHER ${CLCACHEWRAPPER}) set(CMAKE_CXX_COMPILER_LAUNCHER ${CLCACHEWRAPPER}) + else() + message(STATUS "Building clcachewrapper - Failed") + message(WARNING "clcachewrapper could not be built, so clcache will not be used.") endif() else() set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_EXE}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 88834b6e2..fc45f340e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,13 +16,18 @@ set(BASE64ENCODER ${CMAKE_BINARY_DIR}/base64encoder) +message(STATUS "Building base64encoder") + try_compile(BASE64ENCODER_EXE ${CMAKE_BINARY_DIR} SOURCES ${CMAKE_SOURCE_DIR}/cmake/base64encoder.cpp ${CMAKE_SOURCE_DIR}/extern/modp_b64/modp_b64.cc COPY_FILE ${BASE64ENCODER}) -if(NOT BASE64ENCODER_EXE) - message(FATAL_ERROR "base64encoder could not be built...") +if(BASE64ENCODER_EXE) + message(STATUS "Building base64encoder - Success") +else() + message(STATUS "Building base64encoder - Failed") + message(FATAL_ERROR "base64encoder could not be built.") endif() # Copy of our version file over. From 931bdfdab56c9d9d765a12c6876848ca46223cb6 Mon Sep 17 00:00:00 2001 From: Alan Garny Date: Fri, 19 Jun 2026 14:22:25 +1200 Subject: [PATCH 3/4] LLVM+Clang: upgraded to version 22.1.8. --- .github/workflows/buildThirdPartyLibrary.yml | 4 + .github/workflows/ci.yml | 30 +- CMakeLists.txt | 10 +- cmake/common.cmake | 21 ++ cmake/environmentchecks.cmake | 1 - cmake/formatting/CMakeLists.txt | 1 + cmake/packaging/patch.in.cmake | 2 +- cmake/staticarchiveextractor.cpp | 341 +++++++++++++++++++ src/3rdparty/LLVMClang/CMakeLists.txt | 70 +++- src/3rdparty/LLVMClang/README.md | 2 +- src/CMakeLists.txt | 53 +-- src/bindings/javascript/CMakeLists.txt | 5 - src/misc/compiler.cpp | 14 +- tests/api/version/tests.cpp | 8 +- tests/bindings/javascript/version.test.js | 8 +- tests/bindings/python/test_version.py | 8 +- tests/install/CMakeLists.txt | 2 +- tests/misc/compilertests.cpp | 34 +- 18 files changed, 504 insertions(+), 110 deletions(-) create mode 100644 cmake/staticarchiveextractor.cpp diff --git a/.github/workflows/buildThirdPartyLibrary.yml b/.github/workflows/buildThirdPartyLibrary.yml index 9d767de55..8c752b6d3 100644 --- a/.github/workflows/buildThirdPartyLibrary.yml +++ b/.github/workflows/buildThirdPartyLibrary.yml @@ -110,6 +110,10 @@ jobs: uses: opencor/buildcache-action@v1 with: cache_key: webassembly + - name: Install LLVM + run: | + brew install llvm + echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH - name: Install Emscripten run: brew install emscripten - name: Configure libOpenCOR (for a specific third-party library) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60cd30063..8f915e092 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON + install_prefix: cmake - name: 'Windows shared library (Intel)' os: windows-2022 arch: amd64 @@ -41,6 +42,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON + install_prefix: cmake copy_dll: ON - name: 'Windows static library (ARM)' os: windows-11-arm @@ -56,6 +58,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON + install_prefix: cmake - name: 'Windows shared library (ARM)' os: windows-11-arm arch: amd64_arm64 @@ -70,6 +73,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON + install_prefix: cmake copy_dll: ON - name: 'Linux static library (Intel)' os: ubuntu-24.04 @@ -84,7 +88,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'Linux shared library (Intel)' os: ubuntu-24.04 build_type: Release @@ -98,7 +102,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'Linux static library (ARM)' os: ubuntu-24.04-arm build_type: Release @@ -112,7 +116,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'Linux shared library (ARM)' os: ubuntu-24.04-arm build_type: Release @@ -126,7 +130,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'macOS static library (Intel)' os: macos-15-intel build_type: Release @@ -140,7 +144,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'macOS shared library (Intel)' os: macos-15-intel build_type: Release @@ -154,7 +158,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'macOS static library (ARM)' os: macos-15 build_type: Release @@ -168,7 +172,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'macOS shared library (ARM)' os: macos-15 build_type: Release @@ -182,7 +186,7 @@ jobs: unit_testing: ON target: unit_testing install_uninstall_and_package: ON - use_install_prefix: ON + install_prefix: lib/cmake - name: 'JavaScript bindings' os: ubuntu-24.04 build_type: Release @@ -297,7 +301,7 @@ jobs: python_support: OFF shared_libs: ON unit_testing: ON - context: PATH=/opt/homebrew/opt/llvm@20/bin:$PATH CC=/opt/homebrew/opt/llvm@20/bin/clang CXX=/opt/homebrew/opt/llvm@20/bin/clang++ + context: PATH=/opt/homebrew/opt/llvm/bin:$PATH CC=/opt/homebrew/opt/llvm/bin/clang CXX=/opt/homebrew/opt/llvm/bin/clang++ target: code_coverage - name: 'Memory checks' os: macos-15 @@ -355,7 +359,7 @@ jobs: arch: ${{ matrix.arch }} - name: Install LLVM if: ${{ matrix.code_coverage == 'ON' }} - run: brew install --overwrite llvm@20 + run: brew install llvm - name: Install Clang if: ${{ matrix.code_analysis == 'ON' }} run: | @@ -403,7 +407,7 @@ jobs: - name: Configure libOpenCOR shell: bash run: | - if [ '${{ matrix.use_install_prefix }}' == 'ON' ]; then export D_INSTALL_PREFIX='-DINSTALL_PREFIX=${{ github.workspace }}/install'; fi + if [ '${{ matrix.install_prefix }}' != '' ]; then export D_INSTALL_PREFIX='-DINSTALL_PREFIX=${{ github.workspace }}/install'; fi ${{ matrix.context }} cmake -G Ninja -S . -B build -DBUILD_TYPE=${{ matrix.build_type }} -DCODE_ANALYSIS=${{ matrix.code_analysis }} -DCODE_COVERAGE=${{ matrix.code_coverage }} -DDOCUMENTATION=${{ matrix.documentation }} $D_INSTALL_PREFIX -DJAVASCRIPT_BINDINGS=${{ matrix.javascript_support }} -DJAVASCRIPT_UNIT_TESTING=${{ matrix.javascript_support }} -DMEMORY_CHECKS=${{ matrix.memory_checks }} -DPYTHON_BINDINGS=${{ matrix.python_support }} -DPYTHON_UNIT_TESTING=${{ matrix.python_support }} -DSHARED_LIBS=${{ matrix.shared_libs }} -DUNIT_TESTING=${{ matrix.unit_testing }} - name: Build libOpenCOR if: ${{ (matrix.install_uninstall_and_package == 'ON') || (matrix.javascript_support == 'ON') || (matrix.python_support == 'ON') }} @@ -454,10 +458,10 @@ jobs: shell: bash run: | cd tests/install - if [ '${{ matrix.use_install_prefix }}' == 'ON' ]; then export D_CMAKE_PREFIX_PATH='-DCMAKE_PREFIX_PATH=${{ github.workspace }}/install'; fi + if [ '${{ matrix.install_prefix }}' != '' ]; then export D_CMAKE_PREFIX_PATH='-DCMAKE_PREFIX_PATH=${{ github.workspace }}/install/${{ matrix.install_prefix }}'; fi cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} $D_CMAKE_PREFIX_PATH cmake --build build - if [ '${{ matrix.copy_dll }}' == 'ON' ]; then cp "C:/Program Files (x86)/libOpenCOR/bin/libOpenCOR.dll" build; fi + if [ '${{ matrix.copy_dll }}' == 'ON' ]; then cp "${{ github.workspace }}/install/bin/libOpenCOR.dll" build; fi build/testInstall - name: Uninstall libOpenCOR if: ${{ matrix.install_uninstall_and_package == 'ON' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index bf0e0540a..fc5d10a37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,15 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.15) - -# Some CMake policies. - -foreach(POLICY CMP0096 CMP0144) - if(POLICY ${POLICY}) - cmake_policy(SET ${POLICY} NEW) - endif() -endforeach() +cmake_minimum_required(VERSION 3.27) # Project details. diff --git a/cmake/common.cmake b/cmake/common.cmake index 1920cc9d2..d834ee71e 100644 --- a/cmake/common.cmake +++ b/cmake/common.cmake @@ -42,8 +42,21 @@ function(configure_target TARGET) # Ignore some MSVC warnings. if(BUILDING_USING_MSVC) + # Suppress the warning about needing to export classes from a DLL when using the /MD or /MDd options, which is + # the case for all our targets, as we want to be able to link them with both static and dynamic libraries. This + # warning is triggered by the use of std::string in our public API, but it doesn't cause any issues as long as + # we are consistent with the runtime library we are using (which we are, as we use the same runtime library for + # all our targets). + target_compile_options(${TARGET} PRIVATE /wd4251) + + # Suppress warnings from SYSTEM (external) headers, which includes all third-party library headers (LLVM+Clang, + # libcurl, libxml2, etc.). This avoids having to manually wrap every third-party include with + # #pragma warning(disable/default: ...) in each source file. + + target_compile_options(${TARGET} PRIVATE + /wd4702) endif() # Treat warnings as errors. @@ -69,6 +82,14 @@ function(configure_target TARGET) endif() endif() + # Add the /Zc:preprocessor option to avoid multiple OPT_ enums defaulting to the exact same name when using + # LLVM+Clang. + + if(BUILDING_USING_MSVC) + target_compile_options(${TARGET} PRIVATE + /Zc:preprocessor) + endif() + # Analyse the code. if(LIBOPENCOR_CODE_ANALYSIS) diff --git a/cmake/environmentchecks.cmake b/cmake/environmentchecks.cmake index 8d2427035..387027b34 100644 --- a/cmake/environmentchecks.cmake +++ b/cmake/environmentchecks.cmake @@ -145,7 +145,6 @@ if(NOT BUILDCACHE_EXE) endif() endif() -find_program(7Z_EXE NAMES ${PREFERRED_7Z_NAMES} 7z) find_program(BIOME_EXE NAMES ${PREFERRED_BIOME_NAMES} biome) find_program(RUFF_EXE NAMES ${PREFERRED_RUFF_NAMES} ruff) find_program(CLANG_FORMAT_EXE NAMES ${PREFERRED_CLANG_FORMAT_NAMES} clang-format) diff --git a/cmake/formatting/CMakeLists.txt b/cmake/formatting/CMakeLists.txt index 0cdb00cd2..0a0522aab 100644 --- a/cmake/formatting/CMakeLists.txt +++ b/cmake/formatting/CMakeLists.txt @@ -19,6 +19,7 @@ if(FORMAT_CODE_AVAILABLE) set(GIT_FILES ${CMAKE_SOURCE_DIR}/cmake/base64encoder.cpp ${CMAKE_SOURCE_DIR}/cmake/clcachewrapper.c + ${CMAKE_SOURCE_DIR}/cmake/staticarchiveextractor.cpp ${GIT_API_HEADER_FILES} ${GIT_API_MODULE_FILE} ${GIT_SOURCE_FILES} diff --git a/cmake/packaging/patch.in.cmake b/cmake/packaging/patch.in.cmake index f32e0c7af..f8da1ca88 100644 --- a/cmake/packaging/patch.in.cmake +++ b/cmake/packaging/patch.in.cmake @@ -7,7 +7,7 @@ file(READ ${CMAKE_FILE} FILE_CONTENTS) # entry to those needed system libraries or remove the INTERFACE_LINK_LIBRARIES entry altogether. if(WIN32) - string(REGEX REPLACE "INTERFACE_LINK_LIBRARIES[^\n]*\n" "INTERFACE_LINK_LIBRARIES \"$;$;$;$;$;$\"\n" FILE_CONTENTS "${FILE_CONTENTS}") + string(REGEX REPLACE "INTERFACE_LINK_LIBRARIES[^\n]*\n" "INTERFACE_LINK_LIBRARIES \"$;$;$;$;$;$;$\"\n" FILE_CONTENTS "${FILE_CONTENTS}") elseif(APPLE) string(REGEX REPLACE "INTERFACE_LINK_LIBRARIES[^\n]*\n" "INTERFACE_LINK_LIBRARIES \"-framework CoreFoundation;-framework SystemConfiguration;$\"\n" FILE_CONTENTS "${FILE_CONTENTS}") else() diff --git a/cmake/staticarchiveextractor.cpp b/cmake/staticarchiveextractor.cpp new file mode 100644 index 000000000..2cd954f47 --- /dev/null +++ b/cmake/staticarchiveextractor.cpp @@ -0,0 +1,341 @@ +/* +Copyright libOpenCOR contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Extract all object files from a static archive (.a) file, ensuring that object files with duplicate names are all +// preserved by prepending a unique index to each output filename. +// +// Handle the following ar formats: +// - Standard POSIX ar (short names in the header field); +// - BSD ar format with #1/longname convention (used by Apple's ar); and +// - GNU/Linux ar format with // string table and /N name references. + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +# include +# include +# include +# include +#endif + +#pragma pack(push, 1) +struct ArHeader +{ + char name[16]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char magic[2]; +}; +#pragma pack(pop) + +constexpr auto ArHeaderSize = sizeof(ArHeader); + +static_assert(ArHeaderSize == 60, "The ar header must be exactly 60 bytes long."); + +int main(int pArgC, char *pArgV[]) +{ + // Validate command-line arguments. + + if (pArgC != 2) { + std::cerr << "Usage: " << pArgV[0] << " \n"; + + return 1; + } + + // Validate the archive path. + + std::filesystem::path archivePath(pArgV[1]); + + if (!std::filesystem::is_regular_file(archivePath)) { + std::cerr << "Error: " << archivePath.string() << " is not a file.\n"; + + return 1; + } + + // Read the entire archive into memory using the fastest available method for the platform: + // - Windows: single bulk read; + // - Linux/macOS: memory-mapped I/O for zero-copy access. + + const char *data = nullptr; + size_t dataSize = 0; + +#ifdef _WIN32 + std::ifstream file(archivePath, std::ios::binary); + + if (!file) { + std::cerr << "Error: could not open " << archivePath.string() << ".\n"; + + return 1; + } + + file.seekg(0, std::ios::end); + + dataSize = static_cast(file.tellg()); + + file.seekg(0, std::ios::beg); + + std::vector fileBuffer(dataSize); + + file.read(fileBuffer.data(), static_cast(dataSize)); + file.close(); + + data = fileBuffer.data(); +#else + struct stat st; + + if (::stat(archivePath.c_str(), &st) != 0) { + std::cerr << "Error: could not access " << archivePath.string() << ".\n"; + + return 1; + } + + dataSize = static_cast(st.st_size); + + auto fd {::open(archivePath.c_str(), O_RDONLY)}; + + if (fd == -1) { + std::cerr << "Error: could not open " << archivePath.string() << ".\n"; + + return 1; + } + + auto mapped {::mmap(nullptr, dataSize, PROT_READ, MAP_PRIVATE, fd, 0)}; + + ::close(fd); + + if (mapped == MAP_FAILED) { + std::cerr << "Error: could not mmap " << archivePath.string() << ".\n"; + + return 1; + } + + data = static_cast(mapped); +#endif + + // Check the archive magic. + + if ((dataSize < 8) || (std::memcmp(data, "!\n", 8) != 0)) { + std::cerr << "Error: " << archivePath.string() << " is not a valid ar archive.\n"; + +#ifndef _WIN32 + ::munmap(const_cast(data), dataSize); +#endif + + return 1; + } + + // GNU/Linux ar stores long names in a string table ('//' member). Member headers reference string table entries via + // /N notation. + + size_t pos {8}; + int memberIndex {0}; + std::string stringTable; + auto outputDir {std::filesystem::current_path()}; + + // Pre-allocate a large output buffer (64 KB) shared across all member writes to reduce write syscalls. + + constexpr size_t OutputBufferSize = 65536; + std::vector outputBuffer(OutputBufferSize); + + while (pos + ArHeaderSize <= dataSize) { + // Parse the ar header for the current member. + + ArHeader header; + + std::memcpy(&header, data + pos, ArHeaderSize); + + // Validate the header magic bytes (0x60 0x0A). + + if ((header.magic[0] != '\x60') || (header.magic[1] != '\x0A')) { + break; + } + + // Parse the size field (right-justified decimal, 10 characters). + + long memberSize {}; + + if (auto [ptr, ec] = std::from_chars(header.size, header.size + 10, memberSize); + ec != std::errc {}) { + break; + } + + pos += ArHeaderSize; + + if (pos + memberSize > dataSize) { + break; + } + + // Decode the member name from the 16-byte header field. + + char nameBuf[17] {}; + + std::memcpy(nameBuf, header.name, 16); + + auto nameEnd = 16; + + while ((nameEnd > 0) && (nameBuf[nameEnd - 1] == ' ')) { + --nameEnd; + } + + nameBuf[nameEnd] = '\0'; + + std::string memberName; + const char *memberData = nullptr; + long memberDataSize = 0; + + if ((nameEnd >= 3) && (std::memcmp(nameBuf, "#1/", 3) == 0)) { + // BSD ar format (#1/N): the first N bytes of the data area contain the member name. + + long nameSize {}; + + if (auto [ptr, ec] = std::from_chars(nameBuf + 3, nameBuf + nameEnd, nameSize); + ec != std::errc {}) { + nameSize = 0; + } + + if (nameSize > memberSize) { + nameSize = static_cast(memberSize); + } + + // Strip trailing nulls from the name. + + if (nameSize > 0) { + auto rawEnd = static_cast(nameSize); + + while ((rawEnd > 0) && (data[pos + rawEnd - 1] == '\0')) { + --rawEnd; + } + + memberName.assign(data + pos, rawEnd); + } + + // The actual member data starts immediately after the name. + + memberData = data + pos + nameSize; + memberDataSize = memberSize - nameSize; + } else { + // Standard POSIX or GNU/Linux ar format. + + memberName.assign(nameBuf, static_cast(nameEnd)); + + // POSIX ar appends a '/' to mark the end of the name. + + if (!memberName.empty() && (memberName.back() == '/')) { + memberName.pop_back(); + } + + // The member data starts immediately after the header. + + memberData = data + pos; + memberDataSize = memberSize; + } + + // Get the GNU/Linux ar string table content ('//' member). + + if ((nameEnd == 2) && (nameBuf[0] == '/') && (nameBuf[1] == '/')) { + stringTable.assign(memberData, static_cast(memberDataSize)); + } + + // Resolve GNU/Linux ar extended names (/N format). + + if (!memberName.empty() && (memberName[0] == '/') && (memberName.size() > 1) && !stringTable.empty()) { + auto allDigits {true}; + + for (size_t i = 1; i < memberName.size(); ++i) { + if (!std::isdigit(static_cast(memberName[i]))) { + allDigits = false; + + break; + } + } + + if (allDigits) { + long offset {}; + + if (auto [ptr, ec] = std::from_chars(memberName.data() + 1, memberName.data() + memberName.size(), offset); + (ec == std::errc {}) && (offset >= 0) && (static_cast(offset) < stringTable.size())) { + auto end {static_cast(offset)}; + + while ((end < stringTable.size()) && (stringTable[end] != '/') && (stringTable[end] != '\n') && (stringTable[end] != '\0')) { + ++end; + } + + memberName = stringTable.substr(static_cast(offset), end - static_cast(offset)); + } + } + } + + // Skip special / header-only members (symbol table, string table, etc.). + + if (memberName.empty() || (memberName == " ") || (memberName == "__.SYMDEF") || (memberName == "__.SYMDEF SORTED") || (memberName == "/")) { + pos += memberSize; + + if (memberSize % 2 != 0) { + ++pos; // Odd-sized members are padded with a newline. + } + + continue; + } + + // Write the member with an index prefix to guarantee unique filenames, preventing member name collisions within + // the archive. + + char prefix[16] {}; + + std::snprintf(prefix, sizeof(prefix), "%04d", memberIndex); + + auto outputPath {outputDir / (std::string(prefix) + "_" + std::filesystem::path(memberName).filename().string())}; + std::ofstream outputFile(outputPath, std::ios::binary); + + if (!outputFile) { + std::cerr << "Error: could not write " << outputPath.string() << "\n"; + +#ifndef _WIN32 + ::munmap(const_cast(data), dataSize); +#endif + + return 1; + } + + outputFile.rdbuf()->pubsetbuf(outputBuffer.data(), OutputBufferSize); + outputFile.write(memberData, memberDataSize); + outputFile.close(); + + pos += memberSize; + + if (memberSize % 2 != 0) { + ++pos; // Odd-sized members are padded with a newline. + } + + ++memberIndex; + } + +#ifndef _WIN32 + ::munmap(const_cast(data), dataSize); +#endif + + return 0; +} diff --git a/src/3rdparty/LLVMClang/CMakeLists.txt b/src/3rdparty/LLVMClang/CMakeLists.txt index e6f23514a..307519bd6 100644 --- a/src/3rdparty/LLVMClang/CMakeLists.txt +++ b/src/3rdparty/LLVMClang/CMakeLists.txt @@ -13,9 +13,9 @@ # limitations under the License. set(PACKAGE_NAME LLVMClang) -set(PACKAGE_VERSION 16.0.6) +set(PACKAGE_VERSION 22.1.8) set(PACKAGE_REPOSITORY llvm-project) -set(RELEASE_TAG llvmorg-16.0.6-libopencor) +set(RELEASE_TAG llvmorg-22.1.8-libopencor) set(INSTALL_DIR ${PREBUILT_DIR}/${PACKAGE_NAME}) # Either retrieve or build our package. @@ -24,49 +24,49 @@ if(LIBOPENCOR_PREBUILT_LLVMCLANG) if(EMSCRIPTEN) retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - 9362c8554008534587df73e75e77744dd99dfed9) + 8dcd04b80f13bec0c3fa37b277d06466dcb8ac4a) else() if(WIN32) if(RELEASE_MODE) if(INTEL_MODE) retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - 1182a7df3c015a06e19e75bb6f8972ceefaa2cba) + 7eca038345d2bb5354d469da999fe38ac7a51e96) else() retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - bd28dbf00f1c200936012815dfc990bd3b5e11bd) + 38178c9f5550499a796c24ecebe5d45325e34e66) endif() else() if(INTEL_MODE) retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - b56abbc32573a46207de270819f146b798187c14) + 0a77b2f65286f89a4175cc52ceaf07909a7cec4e) else() retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - 71004b425b4efc2b62f0e77e48a8a3c594fad95f) + b394f358e96039d5d844547b2cafda678a824776) endif() endif() elseif(APPLE) if(INTEL_MODE) retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - 6ff1215e6506f369ba080d441d659c1732ac1c6e) + da706ed5933abedcee5e9f8c6006b71b061c5ebf) else() retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - e9997b0644eaa4228c868e66ab3ee42468c64a4a) + 30642e4e208a800e60b8ada95e15425c89a4b4f9) endif() else() if(INTEL_MODE) retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - cea9d122196d5a69067086dd46393db2f9c1d341) + 540878be30175da91557ab1a9f546383b458a06e) else() retrieve_package(${PACKAGE_NAME} ${PACKAGE_VERSION} ${PACKAGE_REPOSITORY} ${RELEASE_TAG} - 3ec70c1cd21f15b461eefa769079254669d797d3) + 2a68f667a7c571561416451a543024fff9096012) endif() endif() endif() @@ -79,9 +79,16 @@ elseif(NOT ONLY_BUILD_JAVASCRIPT_THIRD_PARTY_LIBRARIES) set(LLVM_TARGETS_TO_BUILD WebAssembly) set(LLVM_HOST_TRIPLE wasm32-unknown-emscripten) + find_program(LLVM_TBLGEN_EXE NAMES llvm-tblgen) + find_program(CLANG_TBLGEN_EXE NAMES clang-tblgen) + + if(NOT LLVM_TBLGEN_EXE OR NOT CLANG_TBLGEN_EXE) + message(FATAL_ERROR "llvm-tblgen and clang-tblgen executables are required to build ${PACKAGE_NAME} with Emscripten.") + endif() + set(TABLEGENS - -DLLVM_TABLEGEN=${NATIVE_PREBUILT_DIR}/${PACKAGE_NAME}/bin/llvm-tblgen - -DCLANG_TABLEGEN=${NATIVE_PREBUILT_DIR}/${PACKAGE_NAME}/bin/clang-tblgen + -DLLVM_TABLEGEN=${LLVM_TBLGEN_EXE} + -DCLANG_TABLEGEN=${CLANG_TBLGEN_EXE} ) else() set(LIBCLANG_BUILD_STATIC ON) @@ -117,17 +124,17 @@ elseif(NOT ONLY_BUILD_JAVASCRIPT_THIRD_PARTY_LIBRARIES) llvm CMAKE_ARGS -DCLANG_BUILD_TOOLS=OFF - -DCLANG_ENABLE_ARCMT=OFF -DCLANG_ENABLE_LIBXML2=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF + -DCLANG_INCLUDE_DOCS=OFF + -DCLANG_INCLUDE_TESTS=OFF -DCLANG_PLUGIN_SUPPORT=OFF - -DCLANG_TOOLING_BUILD_AST_INTROSPECTION=OFF + -DCLANG_TOOL_DICTIONARY_BUILD=OFF -DCLANG_TOOL_HANDLE_CXX_BUILD=OFF -DCLANG_TOOL_HANDLE_LLVM_BUILD=OFF ${CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR} -DLIBCLANG_BUILD_STATIC=${LIBCLANG_BUILD_STATIC} - -DLIBOPENCOR=ON -DLLVM_BUILD_LLVM_C_DYLIB=OFF -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_RUNTIMES=OFF @@ -143,11 +150,12 @@ elseif(NOT ONLY_BUILD_JAVASCRIPT_THIRD_PARTY_LIBRARIES) -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_MODULE_DEBUGGING=OFF -DLLVM_ENABLE_OCAMLDOC=OFF + -DLLVM_ENABLE_ONDISK_CAS=OFF -DLLVM_ENABLE_PEDANTIC=OFF -DLLVM_ENABLE_PLUGINS=OFF -DLLVM_ENABLE_PROJECTS=clang -DLLVM_ENABLE_RTTI=ON - -DLLVM_ENABLE_TERMINFO=OFF + -DLLVM_ENABLE_TELEMETRY=OFF -DLLVM_ENABLE_UNWIND_TABLES=OFF -DLLVM_ENABLE_WARNINGS=OFF -DLLVM_ENABLE_ZLIB=OFF @@ -229,6 +237,8 @@ set(LLVMCLANG_LIBRARIES clangAnalysis clangAnalysisFlowSensitive clangAnalysisFlowSensitiveModels + clangAnalysisLifetimeSafety + clangAnalysisScalable clangAPINotes clangAST clangASTMatchers @@ -246,8 +256,10 @@ set(LLVMCLANG_LIBRARIES clangFrontendTool clangIndex clangIndexSerialization + clangInstallAPI clangInterpreter clangLex + clangOptions clangParse clangRewrite clangRewriteFrontend @@ -265,6 +277,7 @@ set(LLVMCLANG_LIBRARIES clangToolingRefactoring clangToolingSyntax clangTransformer + LLVMABI LLVMAggressiveInstCombine LLVMAnalysis LLVMAsmParser @@ -273,15 +286,20 @@ set(LLVMCLANG_LIBRARIES LLVMBitReader LLVMBitstreamReader LLVMBitWriter + LLVMCAS LLVMCFGuard LLVMCFIVerify + LLVMCGData LLVMCodeGen + LLVMCodeGenTypes LLVMCore LLVMCoroutines LLVMCoverage + LLVMDebugInfoBTF LLVMDebugInfoCodeView LLVMDebuginfod LLVMDebugInfoDWARF + LLVMDebugInfoDWARFLowLevel LLVMDebugInfoGSYM LLVMDebugInfoLogicalView LLVMDebugInfoMSF @@ -289,19 +307,27 @@ set(LLVMCLANG_LIBRARIES LLVMDemangle LLVMDiff LLVMDlltoolDriver + LLVMDTLTO + LLVMDWARFCFIChecker LLVMDWARFLinker + LLVMDWARFLinkerClassic LLVMDWARFLinkerParallel LLVMDWP LLVMExecutionEngine LLVMExegesis LLVMExtensions LLVMFileCheck + LLVMFrontendAtomic + LLVMFrontendDirective + LLVMFrontendDriver LLVMFrontendHLSL + LLVMFrontendOffloading LLVMFrontendOpenACC LLVMFrontendOpenMP LLVMFuzzerCLI LLVMFuzzMutate LLVMGlobalISel + LLVMHipStdPar LLVMInstCombine LLVMInstrumentation LLVMInterfaceStub @@ -324,23 +350,31 @@ set(LLVMCLANG_LIBRARIES LLVMObjCopy LLVMObject LLVMObjectYAML + LLVMOptDriver LLVMOption + LLVMOrcDebugging LLVMOrcJIT LLVMOrcShared LLVMOrcTargetProcess LLVMPasses + LLVMPlugins LLVMProfileData LLVMRemarks LLVMRuntimeDyld + LLVMSandboxIR LLVMScalarOpts LLVMSelectionDAG LLVMSupport + LLVMSupportLSP LLVMSymbolize LLVMTableGen - LLVMTableGenGlobalISel + LLVMTableGenBasic + LLVMTableGenCommon LLVMTarget LLVMTargetParser + LLVMTelemetry LLVMTextAPI + LLVMTextAPIBinaryReader LLVMTransformUtils LLVMVectorize LLVMWindowsDriver diff --git a/src/3rdparty/LLVMClang/README.md b/src/3rdparty/LLVMClang/README.md index bccc69af9..8f80d3d52 100644 --- a/src/3rdparty/LLVMClang/README.md +++ b/src/3rdparty/LLVMClang/README.md @@ -1 +1 @@ -Our copy of LLVM+Clang 16.0.6 requires the changes listed [here](https://github.com/opencor/llvm-project/compare/llvmorg-16.0.6...opencor:llvm-project:llvmorg-16.0.6-libopencor) to build and work correctly with libOpenCOR. +Our copy of LLVM+Clang 22.1.8 requires the changes listed [here](https://github.com/opencor/llvm-project/compare/llvmorg-22.1.8...opencor:llvm-project:llvmorg-22.1.8-libopencor) to build and work correctly with libOpenCOR. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 63a77d6db..7e39777c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -369,13 +369,33 @@ else() # against all of its dependencies. if(NOT LIBOPENCOR_SHARED_LIBS) + # Build the static archive extractor that will be used to extract the object files from our various packages. It + # handles duplicate object names (e.g., two object files named X86.cpp.o within the same library) by prepending + # a unique index to each output filename, which ar -x cannot do since the second extraction silently overwrites + # the first, losing symbols. + + set(STATIC_ARCHIVE_EXTRACTOR ${CMAKE_BINARY_DIR}/staticarchiveextractor) + + message(STATUS "Building staticarchiveextractor") + + try_compile(STATIC_ARCHIVE_EXTRACTOR_EXE ${CMAKE_BINARY_DIR} + SOURCES ${CMAKE_SOURCE_DIR}/cmake/staticarchiveextractor.cpp + COPY_FILE ${STATIC_ARCHIVE_EXTRACTOR}) + + if(STATIC_ARCHIVE_EXTRACTOR_EXE) + message(STATUS "Building staticarchiveextractor - Success") + else() + message(STATUS "Building staticarchiveextractor - Failed") + message(FATAL_ERROR "staticarchiveextractor could not be built.") + endif() + # Retrieve the path to our various packages. set(PACKAGES_DIR ${CMAKE_BINARY_DIR}/packages) file(GLOB_RECURSE PACKAGES ${PREBUILT_DIR}/*${CMAKE_STATIC_LIBRARY_SUFFIX}) - # Extract the object files from our various packages. + # Extract the object files from our various packages, handling duplicate object names. set(PACKAGES_OBJECT_FILES) @@ -386,30 +406,13 @@ else() file(MAKE_DIRECTORY ${PACKAGE_DIR}) - if(WIN32) - if(7Z_EXE) - execute_process(COMMAND ${7Z_EXE} e ${PACKAGE} -bso0 - WORKING_DIRECTORY ${PACKAGE_DIR}) - else() - execute_process(COMMAND ${CMAKE_AR} /NOLOGO /LIST ${PACKAGE} - OUTPUT_VARIABLE PACKAGE_FILES - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(REPLACE "\n" ";" PACKAGE_FILES ${PACKAGE_FILES}) - - foreach(PACKAGE_FILE ${PACKAGE_FILES}) - string(REGEX MATCH ".*\\${CMAKE_CXX_OUTPUT_EXTENSION}$" IS_OBJECT_FILE ${PACKAGE_FILE}) - - if(IS_OBJECT_FILE) - execute_process(COMMAND ${CMAKE_AR} /NOLOGO /EXTRACT:${PACKAGE_FILE} ${PACKAGE} - WORKING_DIRECTORY ${PACKAGE_DIR}) - endif() - endforeach() - endif() - else() - execute_process(COMMAND ${CMAKE_AR} -x ${PACKAGE} - WORKING_DIRECTORY ${PACKAGE_DIR}) - endif() + message(STATUS "Extracting object files from ${PACKAGE}") + + execute_process(COMMAND ${STATIC_ARCHIVE_EXTRACTOR} ${PACKAGE} + WORKING_DIRECTORY ${PACKAGE_DIR}) + + message(STATUS "Extracting object files from ${PACKAGE} - done") + file(GLOB_RECURSE PACKAGE_OBJECT_FILES ${PACKAGE_DIR}/*${CMAKE_CXX_OUTPUT_EXTENSION}) diff --git a/src/bindings/javascript/CMakeLists.txt b/src/bindings/javascript/CMakeLists.txt index 8818d2dc1..3b8ee40ff 100644 --- a/src/bindings/javascript/CMakeLists.txt +++ b/src/bindings/javascript/CMakeLists.txt @@ -60,10 +60,6 @@ if(EMSCRIPTEN OR LIBOPENCOR_JAVASCRIPT_BINDINGS) set(JAVASCRIPT_BINDINGS_TARGET ${CMAKE_PROJECT_NAME}_JavaScript CACHE INTERNAL "JavaScript bindings target.") - if(NOT LIBOPENCOR_PREBUILT_LLVMCLANG) - set(NATIVE_PREBUILT_DIR -DNATIVE_PREBUILT_DIR=${PREBUILT_DIR}) - endif() - add_custom_target(${JAVASCRIPT_BINDINGS_TARGET} COMMAND ${EMCMAKE_EXE} ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" -S ${CMAKE_SOURCE_DIR} -B build -DBUILDCACHE_EXE=${BUILDCACHE_EXE} @@ -83,7 +79,6 @@ if(EMSCRIPTEN OR LIBOPENCOR_JAVASCRIPT_BINDINGS) -DLIBOPENCOR_PREBUILT_SUNDIALS=${LIBOPENCOR_PREBUILT_SUNDIALS} -DLIBOPENCOR_PREBUILT_ZIPPER=${LIBOPENCOR_PREBUILT_ZIPPER} -DLIBOPENCOR_PREBUILT_ZLIB=${LIBOPENCOR_PREBUILT_ZLIB} - ${NATIVE_PREBUILT_DIR} -DONLY_BUILD_THIRD_PARTY_LIBRARIES=${ONLY_BUILD_THIRD_PARTY_LIBRARIES} -DREAL_CMAKE_PROJECT_NAME=${CMAKE_PROJECT_NAME_LC} COMMAND ${CMAKE_COMMAND} --build build) diff --git a/src/misc/compiler.cpp b/src/misc/compiler.cpp index 36e54729c..16e7b941a 100644 --- a/src/misc/compiler.cpp +++ b/src/misc/compiler.cpp @@ -27,9 +27,9 @@ limitations under the License. #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/MC/TargetRegistry.h" -#include "llvm/Support/Host.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/Host.h" #include "llvm-c/Core.h" #include @@ -80,12 +80,12 @@ bool Compiler::Impl::compile(const std::string &pCode) // Create a diagnostics engine. - auto diagnosticOptions {llvm::IntrusiveRefCntPtr(std::make_unique())}; + auto diagnosticOptions {std::make_unique()}; std::string diagnostics; llvm::raw_string_ostream outputStream(diagnostics); auto diagnosticsEngine {llvm::IntrusiveRefCntPtr(std::make_unique(llvm::IntrusiveRefCntPtr(std::make_unique()), - &*diagnosticOptions, - std::make_unique(outputStream, &*diagnosticOptions).release()))}; + *diagnosticOptions, + new clang::TextDiagnosticPrinter(outputStream, *diagnosticOptions)))}; diagnosticsEngine->setWarningsAsErrors(true); @@ -314,7 +314,7 @@ extern double atanh(double); if (target == nullptr) { error[0] = static_cast(tolower(error[0])); - const auto targetTriple {module->getTargetTriple()}; + const auto targetTriple {module->getTargetTriple().str()}; std::string targetError; targetError.reserve(targetTriple.size() + error.size() + 32); // NOLINT @@ -348,7 +348,7 @@ extern double atanh(double); llvm::SmallVector outputBuffer; llvm::raw_svector_ostream output(outputBuffer); - if (targetMachine->addPassesToEmitFile(passManager, output, nullptr, llvm::CGFT_ObjectFile)) { + if (targetMachine->addPassesToEmitFile(passManager, output, nullptr, llvm::CodeGenFileType::ObjectFile)) { addError("The target machine cannot emit some WebAssembly code."); return false; @@ -442,7 +442,7 @@ bool Compiler::Impl::addFunction(const std::string &pName, void *pFunction) // name, and function. const bool res {!mLljit->getMainJITDylib().define(llvm::orc::absoluteSymbols({ - {mLljit->mangleAndIntern(pName), llvm::JITEvaluatedSymbol(llvm::pointerToJITTargetAddress(pFunction), llvm::JITSymbolFlags::Exported)}, + {mLljit->mangleAndIntern(pName), llvm::orc::ExecutorSymbolDef(llvm::orc::ExecutorAddr::fromPtr(pFunction), llvm::JITSymbolFlags::Exported)}, }))}; # ifndef CODE_COVERAGE_ENABLED diff --git a/tests/api/version/tests.cpp b/tests/api/version/tests.cpp index 4678ff472..764a09113 100644 --- a/tests/api/version/tests.cpp +++ b/tests/api/version/tests.cpp @@ -61,8 +61,8 @@ TEST(VersionTest, libOpenCOR) TEST(VersionTest, Clang) { - EXPECT_EQ(0x160006U, libOpenCOR::clangVersion()); - EXPECT_EQ("16.0.6", libOpenCOR::clangVersionString()); + EXPECT_EQ(0x220108U, libOpenCOR::clangVersion()); + EXPECT_EQ("22.1.8", libOpenCOR::clangVersionString()); } TEST(VersionTest, libCellML) @@ -91,8 +91,8 @@ TEST(VersionTest, libSEDML) TEST(VersionTest, LLVM) { - EXPECT_EQ(0x160006U, libOpenCOR::llvmVersion()); - EXPECT_EQ("16.0.6", libOpenCOR::llvmVersionString()); + EXPECT_EQ(0x220108U, libOpenCOR::llvmVersion()); + EXPECT_EQ("22.1.8", libOpenCOR::llvmVersionString()); } TEST(VersionTest, SUNDIALS) diff --git a/tests/bindings/javascript/version.test.js b/tests/bindings/javascript/version.test.js index 246419ec8..f11f8c31c 100644 --- a/tests/bindings/javascript/version.test.js +++ b/tests/bindings/javascript/version.test.js @@ -52,8 +52,8 @@ test.describe('Version tests', () => { }); test('Clang', () => { - assert.strictEqual(loc.clangVersion(), 0x160006); - assert.strictEqual(loc.clangVersionString(), '16.0.6'); + assert.strictEqual(loc.clangVersion(), 0x220108); + assert.strictEqual(loc.clangVersionString(), '22.1.8'); }); test('libCellML', () => { @@ -72,8 +72,8 @@ test.describe('Version tests', () => { }); test('LLVM', () => { - assert.strictEqual(loc.llvmVersion(), 0x160006); - assert.strictEqual(loc.llvmVersionString(), '16.0.6'); + assert.strictEqual(loc.llvmVersion(), 0x220108); + assert.strictEqual(loc.llvmVersionString(), '22.1.8'); }); test('SUNDIALS', () => { diff --git a/tests/bindings/python/test_version.py b/tests/bindings/python/test_version.py index a6763a56b..c8e44bcef 100644 --- a/tests/bindings/python/test_version.py +++ b/tests/bindings/python/test_version.py @@ -56,12 +56,12 @@ def test_version_string(): def test_clang_version(): assert isinstance(loc.clang_version(), int) - assert loc.clang_version() == 0x160006 + assert loc.clang_version() == 0x220108 def test_clang_version_string(): assert isinstance(loc.clang_version_string(), str) - assert loc.clang_version_string() == "16.0.6" + assert loc.clang_version_string() == "22.1.8" def test_libcellml_version(): @@ -106,12 +106,12 @@ def test_libsedml_version_string(): def test_llvm_version(): assert isinstance(loc.llvm_version(), int) - assert loc.llvm_version() == 0x160006 + assert loc.llvm_version() == 0x220108 def test_llvm_version_string(): assert isinstance(loc.llvm_version_string(), str) - assert loc.llvm_version_string() == "16.0.6" + assert loc.llvm_version_string() == "22.1.8" def test_sundials_version(): diff --git a/tests/install/CMakeLists.txt b/tests/install/CMakeLists.txt index b3ac7edfa..a05af6b07 100644 --- a/tests/install/CMakeLists.txt +++ b/tests/install/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.27) project(testInstall) diff --git a/tests/misc/compilertests.cpp b/tests/misc/compilertests.cpp index 85002a91a..d2b7a2b07 100644 --- a/tests/misc/compilertests.cpp +++ b/tests/misc/compilertests.cpp @@ -43,7 +43,7 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_01 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected identifier or '(':\nvoid\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected identifier or '(':\n 35 | void\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("void")); @@ -53,8 +53,8 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_02 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Variable has incomplete type 'void':\nvoid function\n ^"}, - {libOpenCOR::Issue::Type::ERROR, "Expected ';' after top level declarator:\nvoid function\n ^\n ;"}, + {libOpenCOR::Issue::Type::ERROR, "Variable has incomplete type 'void':\n 35 | void function\n | ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected ';' after top level declarator:\n 35 | void function\n | ^\n | ;"}, }}; EXPECT_FALSE(mCompiler->compile("void function")); @@ -64,9 +64,9 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_03 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected parameter declarator:\nvoid function(\n ^"}, - {libOpenCOR::Issue::Type::ERROR, "Expected ')' to match this '(':\nvoid function(\n ^"}, - {libOpenCOR::Issue::Type::ERROR, "Expected function body after function declarator:\nvoid function(\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected parameter declarator:\n 35 | void function(\n | ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected ')' to match this '(':\n 35 | void function(\n | ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected function body after function declarator:\n 35 | void function(\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("void function(")); @@ -76,7 +76,7 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_04 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected function body after function declarator:\nvoid function()\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected function body after function declarator:\n 35 | void function()\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("void function()")); @@ -86,7 +86,7 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_05 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected '}':\nvoid function() {\n ^\nto match this '{':\nvoid function() {\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected '}':\n 35 | void function() {\n | ^\nto match this '{':\n 35 | void function() {\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("void function() {")); @@ -105,7 +105,7 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_06 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Non-void function does not return a value:\ndouble function() {}\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Non-void function does not return a value:\n 35 | double function() {}\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("double function() {}")); @@ -115,8 +115,8 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_07 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected expression:\ndouble function() { return\n ^"}, - {libOpenCOR::Issue::Type::ERROR, "Expected '}' to match this '{':\ndouble function() { return\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected expression:\n 35 | double function() { return\n | ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected '}' to match this '{':\n 35 | double function() { return\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("double function() { return")); @@ -126,8 +126,8 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_08 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected ';' after return statement:\ndouble function() { return 3.0\n ^\n ;"}, - {libOpenCOR::Issue::Type::ERROR, "Expected '}' to match this '{':\ndouble function() { return 3.0\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected ';' after return statement:\n 35 | double function() { return 3.0\n | ^\n | ;"}, + {libOpenCOR::Issue::Type::ERROR, "Expected '}' to match this '{':\n 35 | double function() { return 3.0\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("double function() { return 3.0")); @@ -137,7 +137,7 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_09 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected '}':\ndouble function() { return 3.0;\n ^\nto match this '{':\ndouble function() { return 3.0;\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected '}':\n 35 | double function() { return 3.0;\n | ^\nto match this '{':\n 35 | double function() { return 3.0;\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("double function() { return 3.0;")); @@ -153,7 +153,7 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_10 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected identifier or '(':\ndouble .function() { return 3.0; }\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected identifier or '(':\n 35 | double .function() { return 3.0; }\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("double .function() { return 3.0; }")); @@ -163,8 +163,8 @@ TEST_F(CompilerTest, basic) static const libOpenCOR::ExpectedIssues EXPECTED_ISSUES_11 {{ {libOpenCOR::Issue::Type::ERROR, "The given code could not be compiled."}, - {libOpenCOR::Issue::Type::ERROR, "Expected expression:\ndouble function() { return 3.0+*-/a; }\n ^"}, - {libOpenCOR::Issue::Type::ERROR, "Use of undeclared identifier 'a':\ndouble function() { return 3.0+*-/a; }\n ^"}, + {libOpenCOR::Issue::Type::ERROR, "Expected expression:\n 35 | double function() { return 3.0+*-/a; }\n | ^"}, + {libOpenCOR::Issue::Type::ERROR, "Use of undeclared identifier 'a':\n 35 | double function() { return 3.0+*-/a; }\n | ^"}, }}; EXPECT_FALSE(mCompiler->compile("double function() { return 3.0+*-/a; }")); From 01a6e05fd5920ce6aa01e0162a610dc6beeedb75 Mon Sep 17 00:00:00 2001 From: Alan Garny Date: Fri, 19 Jun 2026 14:54:20 +1200 Subject: [PATCH 4/4] JavaScript tests: use an infinite number of listeners. --- tests/bindings/javascript/utils.in.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/bindings/javascript/utils.in.js b/tests/bindings/javascript/utils.in.js index 44a13e65d..f7497c612 100644 --- a/tests/bindings/javascript/utils.in.js +++ b/tests/bindings/javascript/utils.in.js @@ -15,8 +15,11 @@ limitations under the License. */ import assert from 'node:assert'; +import { setMaxListeners } from 'node:events'; import { readFileSync } from 'node:fs'; +setMaxListeners(Infinity); + export const RESOURCE_LOCATION = '@CMAKE_SOURCE_DIR@/tests/res'; export const REMOTE_BASE_PATH = 'https://raw.githubusercontent.com/opencor/libopencor/master/tests/res';