diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dce04678..b48c493ba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,17 +18,16 @@ jobs: strategy: matrix: config: - - { name: 'Windows MSVC', os: windows-latest, compiler: msvc, shell: bash } - - { name: 'Windows MinGW', os: windows-latest, compiler: mingw, shell: 'msys2 {0}' } - - { name: 'macOS', os: macos-latest, shell: bash } - - { name: 'Ubuntu', os: ubuntu-18.04, shell: bash } + - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } + - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } + - { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } + - { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } + - { name: 'macOS', os: macos-latest } + - { name: 'Ubuntu', os: ubuntu-18.04 } fail-fast: false name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} - defaults: - run: - shell: ${{ matrix.config.shell }} steps: - name: Checkout @@ -36,53 +35,113 @@ jobs: with: submodules: recursive + - name: Set Windows arch identifiers + id: windows-identify + if: ${{ matrix.config.compiler == 'msvc' || matrix.config.compiler == 'mingw' }} + run: | + vswhere_target="${{ matrix.config.arch }}" + msvc_target="${{ matrix.config.arch }}" + mingw_target="${{ matrix.config.arch }}" + + if [ '${{ matrix.config.arch }}' == 'x86' ]; then + msvc_target="Win32" + elif [ '${{ matrix.config.arch }}' == 'x86_64' ]; then + vswhere_target="amd64" + msvc_target="x64" + fi + + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + echo "vswhere target: ${vswhere_target}" + echo "MSVC target: ${msvc_target}" + else + echo "MinGW cross target: ${mingw_target}" + fi + + echo "::set-output name=vswhere-target::${vswhere_target}" + echo "::set-output name=msvc-target::${msvc_target}" + echo "::set-output name=mingw-target::${mingw_target}" + + - name: Set package identifier + id: package-identify + run: | + package_name="furnace-${GITHUB_SHA}" + package_ext="" + if [ '${{ runner.os }}' == 'Windows' ] || [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + package_name="${package_name}-Windows" + if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + package_name="${package_name}-MinGW" + else + package_name="${package_name}-MSVC" + fi + package_name="${package_name}-${{ matrix.config.arch }}" + package_ext="" # Directory, uploading will automatically zip it + elif [ '${{ runner.os }}' == 'macOS' ]; then + package_name="${package_name}-macOS" + package_ext=".dmg" + else + package_name="${package_name}-Linux" + package_ext=".AppImage" + fi + + echo "Package identifier: ${package_name}" + echo "Package file: ${package_name}${package_ext}" + + echo "::set-output name=id::${package_name}" + echo "::set-output name=filename::${package_name}${package_ext}" + - name: Setup Toolchain [Windows MSVC] - if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'msvc' }} + if: ${{ matrix.config.compiler == 'msvc' }} uses: seanmiddleditch/gha-setup-vsdevenv@v3 + with: + arch: ${{ steps.windows-identify.outputs.vswhere-target }} - name: Setup Toolchain [Windows MinGW] - if: ${{ runner.os == 'Windows' && matrix.config.compiler == 'mingw' }} - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: true - install: | - mingw-w64-x86_64-toolchain - mingw-w64-x86_64-cmake - make - - - name: Install Dependencies [macOS] - if: ${{ runner.os == 'macOS' }} + if: ${{ matrix.config.compiler == 'mingw' }} run: | - export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew update - brew install \ - pkg-config \ - sdl2 \ - libsndfile \ - zlib \ - jack + sudo apt update + sudo apt install \ + mingw-w64 \ + mingw-w64-tools - name: Install Dependencies [Ubuntu] - if: ${{ runner.os == 'Linux' }} + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | sudo apt update sudo apt install \ libsdl2-dev \ + libfmt-dev \ + librtmidi-dev \ libsndfile1-dev \ zlib1g-dev \ - libjack-jackd2-dev + libjack-jackd2-dev \ + appstream + wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" + chmod +x appimagetool-x86_64.AppImage - - name: Configure + - name: Configure (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} run: | export USE_WAE=ON export CMAKE_EXTRA_ARGS=() - if [ '${{ runner.os }}' == 'Windows' ]; then - if [ '${{ matrix.config.compiler }}' == 'mingw' ]; then - CMAKE_EXTRA_ARGS+=('-G' 'MSYS Makefiles') - elif [ '${{ matrix.config.compiler }}' == 'msvc' ]; then - # We don't want all the MSVC warnings to cause errors yet - export USE_WAE=OFF + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') + + # FIXME We don't want all the MSVC warnings to cause errors yet + export USE_WAE=OFF + elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') + else + # Test with system libs + CMAKE_EXTRA_ARGS+=( + '-DSYSTEM_FMT=ON' + '-DSYSTEM_LIBSNDFILE=ON' + '-DSYSTEM_RTMIDI=ON' + '-DSYSTEM_ZLIB=ON' + '-DWITH_JACK=ON' + ) + # Too old on Ubuntu + if [ '${{ runner.os }}' == 'macOS' ]; then + CMAKE_EXTRA_ARGS+=('-DSYSTEM_SDL2=ON') fi fi @@ -93,6 +152,59 @@ jobs: -DWARNINGS_ARE_ERRORS=${USE_WAE} \ "${CMAKE_EXTRA_ARGS[@]}" + - name: Build (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + run: | + export VERBOSE=1 + cmake \ + --build ${PWD}/build \ + --config ${{ env.BUILD_TYPE }} \ + --parallel 2 + + - name: Install (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + run: | + cmake \ + --install ${PWD}/build \ + --config ${{ env.BUILD_TYPE }} + + - name: Cleanup (System Libraries) + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + run: | + rm -rf build/ target/ + + - name: Configure + run: | + export USE_WAE=ON + export CMAKE_EXTRA_ARGS=() + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') + + # FIXME We don't want all the MSVC warnings to cause errors yet + export USE_WAE=OFF + + # Force static linking + # 1. Make MSVC runtime configurable + CMAKE_EXTRA_ARGS+=('-DCMAKE_POLICY_DEFAULT_CMP0091=NEW') + # 2. Use static (debug) runtime + if [ '${{ env.BUILD_TYPE }}' == 'Debug' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug') + else + CMAKE_EXTRA_ARGS+=('-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded') + fi + elif [ '${{ matrix.config.compiler }}' == 'mingw' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_TOOLCHAIN_FILE=scripts/Cross-MinGW-${{ steps.windows-identify.outputs.mingw-target }}.cmake') + elif [ '${{ runner.os }}' == 'macOS' ]; then + CMAKE_EXTRA_ARGS+=('-DCMAKE_OSX_DEPLOYMENT_TARGET="10.9"') + fi + + cmake \ + -B ${PWD}/build \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ + -DWARNINGS_ARE_ERRORS=${USE_WAE} \ + "${CMAKE_EXTRA_ARGS[@]}" + - name: Build run: | export VERBOSE=1 @@ -101,8 +213,66 @@ jobs: --config ${{ env.BUILD_TYPE }} \ --parallel 2 - - name: Install + - name: Package [Windows] + if: ${{ runner.os == 'Windows' || matrix.config.compiler == 'mingw' }} run: | - cmake \ - --install ${PWD}/build \ - --config ${{ env.BUILD_TYPE }} + binPath=build + if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + binPath="${binPath}/${{ env.BUILD_TYPE }}" + fi + if [ '${{ matrix.config.compiler }}' == 'mingw' ] && [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then + # arch-specific strip prefix + # TODO maybe extract from cross toolchain files? + toolPrefix="-w64-mingw32-" + if [ '${{ matrix.config.arch }}' == 'x86_64' ]; then + toolPrefix="x86_64${toolPrefix}" + else + toolPrefix="i686${toolPrefix}" + fi + ${toolPrefix}strip -s "${binPath}/furnace.exe" + fi + + mkdir ${{ steps.package-identify.outputs.filename }} + pushd ${{ steps.package-identify.outputs.filename }} + + cp -v ../LICENSE LICENSE.txt + cp -v ../README.md README.txt + cp -vr ../{papers,demos} ../${binPath}/furnace.exe ./ + + popd + + - name: Package [macOS] + if: ${{ runner.os == 'macOS' }} + run: | + pushd build + cpack + mv Furnace-*-Darwin.dmg ../${{ steps.package-identify.outputs.filename }} + popd + + - name: Package [Ubuntu] + if: ${{ runner.os == 'Linux' && matrix.config.compiler != 'mingw' }} + run: | + if [ '${{ env.BUILD_TYPE }}' == 'Release' ]; then + strip -s build/furnace + fi + + mkdir -p target/furnace.AppDir + make -C ${PWD}/build DESTDIR=${PWD}/target/furnace.AppDir install + pushd target + + pushd furnace.AppDir + cp -v usr/share/{icons/hicolor/1024x1024/apps/furnace.png,applications/furnace.desktop} ./ + ln -s furnace.png .DirIcon + mv -v usr/share/metainfo/{furnace.appdata,org.tildearrow.furnace.metainfo}.xml + cp -v ../../res/AppRun ./ + popd + + ../appimagetool-x86_64.AppImage furnace.AppDir + mv Furnace-*.AppImage ../${{ steps.package-identify.outputs.filename }} + popd + + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.package-identify.outputs.id }} + path: ${{ steps.package-identify.outputs.filename }} diff --git a/CMakeLists.txt b/CMakeLists.txt index c5fc06e70..769842f33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,8 +167,13 @@ if (SYSTEM_SDL2) endif() message(STATUS "Using system-installed SDL2") else() - set(SDL_SHARED OFF) - set(SDL_STATIC ON) + set(SDL_SHARED OFF CACHE BOOL "Force no dynamically-linked SDL" FORCE) + set(SDL_STATIC ON CACHE BOOL "Force statically-linked SDL" FORCE) + # https://github.com/libsdl-org/SDL/issues/1481 + # On 2014-06-22 17:15:50 +0000, Sam Lantinga wrote: + # If you link SDL statically, you also need to define HAVE_LIBC so it builds with the C runtime that your application uses. + # This should probably go in a FAQ. + set(SDL_LIBC ON CACHE BOOL "Tell SDL that we want it to use our C runtime (required for proper static linking)" FORCE) add_subdirectory(extern/SDL EXCLUDE_FROM_ALL) list(APPEND DEPENDENCIES_INCLUDE_DIRS extern/SDL/include) list(APPEND DEPENDENCIES_LIBRARIES SDL2-static) diff --git a/extern/pfd-fixed/portable-file-dialogs.h b/extern/pfd-fixed/portable-file-dialogs.h index 41e588acf..008fe0a94 100644 --- a/extern/pfd-fixed/portable-file-dialogs.h +++ b/extern/pfd-fixed/portable-file-dialogs.h @@ -57,7 +57,7 @@ #ifndef PFD_HAS_IFILEDIALOG # define PFD_HAS_IFILEDIALOG 1 # if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION -# if __GXX_ABI_VERSION <= 1013 +# if __GXX_ABI_VERSION <= 1014 # undef PFD_HAS_IFILEDIALOG # define PFD_HAS_IFILEDIALOG 0 # endif @@ -1383,7 +1383,7 @@ inline notify::notify(std::string const &title, /* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; } - ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL + ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL WINAPI { ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); return false; diff --git a/scripts/Cross-MinGW-x86.cmake b/scripts/Cross-MinGW-x86.cmake new file mode 100644 index 000000000..4049ffdd0 --- /dev/null +++ b/scripts/Cross-MinGW-x86.cmake @@ -0,0 +1,4 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR i686) + +include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake) diff --git a/scripts/Cross-MinGW-x86_64.cmake b/scripts/Cross-MinGW-x86_64.cmake new file mode 100644 index 000000000..5b088cb30 --- /dev/null +++ b/scripts/Cross-MinGW-x86_64.cmake @@ -0,0 +1,4 @@ +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +include(${CMAKE_CURRENT_LIST_DIR}/Cross-MinGW.cmake) diff --git a/scripts/Cross-MinGW.cmake b/scripts/Cross-MinGW.cmake new file mode 100644 index 000000000..09871d6bb --- /dev/null +++ b/scripts/Cross-MinGW.cmake @@ -0,0 +1,14 @@ +set(TARGET_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32) + +set(CMAKE_C_COMPILER ${TARGET_PREFIX}-gcc-posix) +set(CMAKE_CXX_COMPILER ${TARGET_PREFIX}-g++-posix) +set(PKG_CONFIG_EXECUTABLE ${TARGET_PREFIX}-pkg-config) + +set(CMAKE_FIND_ROOT_PATH /usr/${TARGET_PREFIX}) + +# Search host system for programs +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# Search target system for libraries, headers & CMake packages +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)