diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6468909 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,151 @@ +name: Cross-Platform Build CI + +on: + push: + branches: + - '**' # Matches every branch push + pull_request: + branches: + - '**' # Matches every pull request target branch + workflow_dispatch: # Allows manual trigger from the GitHub Actions tab + +jobs: + # --------------------------------------------------------------------------- + # Linux Builds (Ubuntu) + # --------------------------------------------------------------------------- + linux: + name: Linux (Ubuntu) + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y libudev-dev ninja-build + + - name: Build Shared Library + run: | + cmake -G Ninja -B build-shared \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=ON \ + -DLIBSERIALPORT_BUILD_EXAMPLES=ON \ + -DCMAKE_INSTALL_PREFIX=stage/shared + cmake --build build-shared + cmake --install build-shared + + - name: Build Static Library + run: | + cmake -G Ninja -B build-static \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DLIBSERIALPORT_BUILD_EXAMPLES=OFF \ + -DCMAKE_INSTALL_PREFIX=stage/static + cmake --build build-static + cmake --install build-static + + - name: Upload Linux Artifacts + uses: actions/upload-artifact@v7 + with: + name: libserialport-linux-x86_64 + path: stage/ + + # --------------------------------------------------------------------------- + # macOS Builds (Apple Silicon & Intel via Universal Binary layout) + # --------------------------------------------------------------------------- + macos: + name: macOS (Apple) + runs-on: macos-latest + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Build Shared Library + run: | + cmake -G Ninja -B build-shared \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=ON \ + -DLIBSERIALPORT_BUILD_EXAMPLES=ON \ + -DCMAKE_INSTALL_PREFIX=stage/shared + cmake --build build-shared + cmake --install build-shared + + - name: Build Static Library + run: | + cmake -G Ninja -B build-static \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DLIBSERIALPORT_BUILD_EXAMPLES=OFF \ + -DCMAKE_INSTALL_PREFIX=stage/static + cmake --build build-static + cmake --install build-static + + - name: Upload macOS Artifacts + uses: actions/upload-artifact@v7 + with: + name: libserialport-macos-universal + path: stage/ + + # --------------------------------------------------------------------------- + # Windows Builds (MSYS2 Environments) + # --------------------------------------------------------------------------- + windows-msys2: + name: Windows (${{ matrix.msys_env }}) + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - msys_env: mingw64 + sys_prefix: mingw-w64-x86_64 + - msys_env: ucrt64 + sys_prefix: mingw-w64-ucrt-x86_64 + - msys_env: clang64 + sys_prefix: mingw-w64-clang-x86_64 + + defaults: + run: + shell: msys2 {0} + + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Setup MSYS2 Subsystem + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.msys_env }} + update: true + install: >- + git + make + ${{ matrix.sys_prefix }}-cc + ${{ matrix.sys_prefix }}-cmake + ${{ matrix.sys_prefix }}-ninja + + - name: Build Shared Library + run: | + cmake -G Ninja -B build-shared \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=ON \ + -DLIBSERIALPORT_BUILD_EXAMPLES=ON \ + -DCMAKE_INSTALL_PREFIX=stage/shared + cmake --build build-shared + cmake --install build-shared + + - name: Build Static Library + run: | + cmake -G Ninja -B build-static \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=OFF \ + -DLIBSERIALPORT_BUILD_EXAMPLES=OFF \ + -DCMAKE_INSTALL_PREFIX=stage/static + cmake --build build-static + cmake --install build-static + + - name: Upload Windows Artifacts + uses: actions/upload-artifact@v7 + with: + name: libserialport-windows-${{ matrix.msys_env }} + path: stage/ diff --git a/.github/workflows/msvc-build.yml b/.github/workflows/msvc-build.yml new file mode 100644 index 0000000..62c156e --- /dev/null +++ b/.github/workflows/msvc-build.yml @@ -0,0 +1,44 @@ +name: MSVC Build All Archs + +on: + push: + branches: ['**'] + pull_request: + branches: ['**'] + +jobs: + build: + name: Build ${{ matrix.arch }} + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - { arch: x86, platform: Win32 } + - { arch: x64, platform: x64 } + - { arch: arm64, platform: ARM64 } + + steps: + - name: Checkout Code + uses: actions/checkout@v6 + + - name: Build Shared Library + run: | + cmake -B build-shared -A ${{ matrix.platform }} -DBUILD_SHARED_LIBS=ON + cmake --build build-shared --config Release + + - name: Build Static Library + run: | + cmake -B build-static -A ${{ matrix.platform }} -DBUILD_SHARED_LIBS=OFF + cmake --build build-static --config Release + + - name: Archive Artifacts + uses: actions/upload-artifact@v7 + with: + name: libserialport-${{ matrix.arch }} + path: | + build-shared/Release/serialport.dll + build-shared/Release/serialport.lib + build-shared/Release/list_ports.exe + build-static/Release/serialport.lib + build-static/Release/list_ports.exe diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..359c2e6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.12) +project(libserialport C) + +# --- 1. Autotools Compatibility & Visibility Definitions --- +if(NOT WIN32) + # Generate an empty config.h in the binary directory to satisfy #include + if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/config.h") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/config.h" "/* Generated by CMake */\n") + endif() + include_directories(${CMAKE_CURRENT_BINARY_DIR}) +endif() + +# Gather common implementation source files +set(SERIALPORT_SOURCES + serialport.c + timing.c +) + +# Platform-specific backend mapping +if(WIN32) + list(APPEND SERIALPORT_SOURCES windows.c) + set(WINDOWS_LIBS setupapi cfgmgr32) +elseif(APPLE) + list(APPEND SERIALPORT_SOURCES macosx.c) + find_library(FRAMEWORK_IOKIT IOKit REQUIRED) + find_library(FRAMEWORK_COREFOUNDATION CoreFoundation REQUIRED) + set(APPLE_LIBS ${FRAMEWORK_IOKIT} ${FRAMEWORK_COREFOUNDATION}) +else() + list(APPEND SERIALPORT_SOURCES linux.c) +endif() + +# --- 2. Core Library Target --- +add_library(serialport ${SERIALPORT_SOURCES}) + +# Use root directory for headers, set as SYSTEM so works everywhere +target_include_directories(serialport SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# Ensure internal visibility macro SP_PRIV is defined across all platforms +target_compile_definitions(serialport PUBLIC SP_PRIV=) + +if(WIN32) + target_link_libraries(serialport PRIVATE ${WINDOWS_LIBS}) + + if(BUILD_SHARED_LIBS) + # Shared Build: Library defines MSBUILD privately so it exports symbols, + # but examples do NOT inherit it so they use dllimport. + target_compile_definitions(serialport PRIVATE LIBSERIALPORT_MSBUILD=1) + else() + # Static Build: Both the library AND the examples MUST see these definitions PUBLICLY. + # This prevents the header from falling back to __declspec(dllimport). + target_compile_definitions(serialport PUBLIC LIBSERIALPORT_MSBUILD=1 SP_API=) + endif() + +elseif(APPLE) + target_link_libraries(serialport PRIVATE ${APPLE_LIBS}) +endif() + +# --- 3. Examples Build Configuration --- +if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/examples") + add_executable(list_ports examples/list_ports.c) + target_link_libraries(list_ports PRIVATE serialport) + target_include_directories(list_ports PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +endif()