diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d82c6d1f..70a05d307 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -331,6 +331,55 @@ jobs: $env:UBSAN_OPTIONS = "print_stacktrace=1" ctest --verbose + build-linux-cross-cppwinrt: + name: 'cross: Cross-build from Linux' + strategy: + matrix: + arch: [i686, x86_64] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Install cross compiler + run: | + arch=${{ matrix.arch }} + sudo apt-get install g++-mingw-w64-${arch/_/-} + sudo update-alternatives --set "${{ matrix.arch }}-w64-mingw32-gcc" "/usr/bin/${{ matrix.arch }}-w64-mingw32-gcc-posix" + sudo update-alternatives --set "${{ matrix.arch }}-w64-mingw32-g++" "/usr/bin/${{ matrix.arch }}-w64-mingw32-g++-posix" + + - name: Cross-build cppwinrt + run: | + cmake -S . -B build/cross_x64/ --toolchain cross-mingw-toolchain.cmake \ + -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_CXX_FLAGS="-static" \ + -DCMAKE_INSTALL_PREFIX=$PWD/install/ + cmake --build build/cross_x64/ --target install -j2 + + - name: Upload cppwinrt.exe + uses: actions/upload-artifact@v3 + with: + name: cross-build-${{ matrix.arch }}-bin + path: install/bin/cppwinrt.exe + + test-linux-cross-cppwinrt: + name: 'cross: Test run on Windows' + needs: build-linux-cross-cppwinrt + strategy: + matrix: + arch: [i686, x86_64] + runs-on: windows-latest + steps: + - name: Fetch cppwinrt executable + uses: actions/download-artifact@v3 + with: + name: cross-build-${{ matrix.arch }}-bin + path: ./ + + - name: Run cppwinrt to build projection + run: | + .\cppwinrt.exe -in local -out .\ -verbose + build-msvc-natvis: name: 'Build natvis' strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index bcc3ca583..b983c4587 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,13 +22,19 @@ add_compile_definitions(_WIN32_WINNT=0x0602) # === prebuild: Generator tool for strings.cpp, strings.h, version.rc === -set(PREBUILD_SRCS - prebuild/main.cpp - prebuild/pch.h -) -add_executable(prebuild ${PREBUILD_SRCS}) -target_compile_definitions(prebuild PRIVATE CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}") -target_include_directories(prebuild PRIVATE cppwinrt/) +if(CMAKE_CROSSCOMPILING) + include(ExternalProject) + ExternalProject_Add(cppwinrt-prebuild + SOURCE_DIR "${PROJECT_SOURCE_DIR}/prebuild" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= "-DCPPWINRT_BUILD_VERSION=${CPPWINRT_BUILD_VERSION}" + ) + ExternalProject_Get_Property(cppwinrt-prebuild INSTALL_DIR) + set(PREBUILD_TOOL "${INSTALL_DIR}/bin/cppwinrt-prebuild") + unset(INSTALL_DIR) +else() + add_subdirectory(prebuild) + set(PREBUILD_TOOL cppwinrt-prebuild) +endif() # === Step to create autogenerated files === @@ -42,9 +48,9 @@ add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/strings.cpp ${PROJECT_BINARY_DIR}/version.rc - COMMAND "${PROJECT_BINARY_DIR}/prebuild.exe" ARGS "${PROJECT_SOURCE_DIR}/strings" "${PROJECT_BINARY_DIR}" + COMMAND "${PREBUILD_TOOL}" ARGS "${PROJECT_SOURCE_DIR}/strings" "${PROJECT_BINARY_DIR}" DEPENDS - prebuild + cppwinrt-prebuild ${PREBUILD_STRINGS_FILES} VERBATIM ) @@ -137,10 +143,11 @@ int main() {} else() set(XMLLITE_DEF_FILE xmllite) endif() + include(CMakeFindBinUtils) add_custom_command( OUTPUT "${PROJECT_BINARY_DIR}/libxmllite.a" - COMMAND dlltool -k -d "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" -l "${PROJECT_BINARY_DIR}/libxmllite.a" + COMMAND "${CMAKE_DLLTOOL}" -k -d "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" -l "${PROJECT_BINARY_DIR}/libxmllite.a" DEPENDS "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" VERBATIM ) @@ -170,7 +177,9 @@ set(winmd_SOURCE_DIR "${SOURCE_DIR}") target_include_directories(cppwinrt PRIVATE "${winmd_SOURCE_DIR}") -include(CTest) -if(BUILD_TESTING) - add_subdirectory(test) +if(NOT CMAKE_CROSSCOMPILING) + include(CTest) + if(BUILD_TESTING) + add_subdirectory(test) + endif() endif() diff --git a/cppwinrt/main.cpp b/cppwinrt/main.cpp index 6f10f8e79..5834d868f 100644 --- a/cppwinrt/main.cpp +++ b/cppwinrt/main.cpp @@ -268,9 +268,17 @@ Where is one or more of: if (settings.verbose) { - char* path = nullptr; - _get_pgmptr(&path); - w.write(" tool: %\n", path); + { + char* path = argv[0]; + char path_buf[32768]; + DWORD path_size = GetModuleFileNameA(nullptr, path_buf, sizeof(path_buf)); + if (path_size) + { + path_buf[sizeof(path_buf) - 1] = 0; + path = path_buf; + } + w.write(" tool: %\n", path); + } w.write(" ver: %\n", CPPWINRT_VERSION_STRING); for (auto&& file : settings.input) diff --git a/cross-mingw-toolchain.cmake b/cross-mingw-toolchain.cmake new file mode 100644 index 000000000..d58bb278d --- /dev/null +++ b/cross-mingw-toolchain.cmake @@ -0,0 +1,42 @@ +# This is a cmake-toolchain(5) file that can be used to cross-build +# cppwinrt.exe fron Linux or other operating systems using a mingw-w64 cross +# toolchain. This should work with both GCC-based and llvm-mingw toolchains. +# +# Example usage with external toolchain: +# +# $ cmake -S . -B build/cross_x64/ \ +# --toolchain cross-mingw-toolchain.cmake \ +# -DMINGW_BIN_PATH=/opt/llvm-mingw/bin \ +# -DCMAKE_BUILD_TYPE=RelWithDebInfo \ +# -DCMAKE_INSTALL_PREFIX=$PWD/install/ +# +# Example usage with toolchain installed system-wide: +# +# $ cmake -S . -B build/cross_i686/ \ +# --toolchain cross-mingw-toolchain.cmake \ +# -DCMAKE_SYSTEM_PROCESSOR=i686 \ +# -DCMAKE_BUILD_TYPE=RelWithDebInfo \ +# -DCMAKE_INSTALL_PREFIX=$PWD/install/ + + +set(CMAKE_SYSTEM_NAME Windows) +if(NOT DEFINED CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR x86_64) +endif() + +set(TOOLCHAIN_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32) + +if(DEFINED MINGW_BIN_PATH) + set(TOOLCHAIN_PREFIX "${MINGW_BIN_PATH}/${TOOLCHAIN_PREFIX}") +endif() + +set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}-gcc") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}-g++") +set(CMAKE_RC_COMPILER "${TOOLCHAIN_PREFIX}-windres") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +unset(TOOLCHAIN_PREFIX) diff --git a/prebuild/CMakeLists.txt b/prebuild/CMakeLists.txt new file mode 100644 index 000000000..da2162d44 --- /dev/null +++ b/prebuild/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.16) + +project(cppwinrt-prebuild LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if(NOT DEFINED CPPWINRT_BUILD_VERSION) + message(FATAL_ERROR "CPPWINRT_BUILD_VERSION has not been defined. You should build the top-level project instead.") +endif() + + +set(PREBUILD_SRCS + main.cpp + pch.h +) +add_executable(cppwinrt-prebuild ${PREBUILD_SRCS}) +target_compile_definitions(cppwinrt-prebuild PRIVATE CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}") +target_include_directories(cppwinrt-prebuild PRIVATE ../cppwinrt/) + +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + install(TARGETS cppwinrt-prebuild) +endif()