Skip to content

Add CMake build and a limited subset of tests for llvm-mingw #1216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,53 @@ jobs:
_build/${{ matrix.arch }}/${{ matrix.config }}/*.lib
_build/${{ matrix.arch }}/${{ matrix.config }}/*.pdb

test-llvm-mingw-cppwinrt:
name: 'llvm-mingw: Build and test'
strategy:
matrix:
arch: [i686, x86_64]
runs-on: windows-latest
steps:
- uses: actions/checkout@v3

- name: Install llvm-mingw toolchain
run: |
$llvm_mingw_version = "20220906"
Invoke-WebRequest "https://github.com/mstorsjo/llvm-mingw/releases/download/${llvm_mingw_version}/llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}.zip" -OutFile llvm-mingw.zip
7z x llvm-mingw.zip
rm llvm-mingw.zip
if (!(Test-Path "$pwd\llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}\bin\clang++.exe")) { return 1 }
Add-Content $env:GITHUB_PATH "$pwd\llvm-mingw-${llvm_mingw_version}-ucrt-${{ matrix.arch }}\bin"

- name: Build cppwinrt
run: |
mkdir build
cd build
cmake ../ -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug
cmake --build . --target cppwinrt

- name: Upload cppwinrt.exe
uses: actions/upload-artifact@v3
with:
name: llvm-mingw-build-${{ matrix.arch }}-bin
path: build/cppwinrt.exe

- name: Build tests
run: |
cd build
cmake --build . --target test-vanilla test_win7

- name: Upload test binaries
uses: actions/upload-artifact@v3
with:
name: llvm-mingw-tests-${{ matrix.arch }}-bin
path: build/test/*.exe

- name: Run tests
run: |
cd build
ctest --verbose

build-msvc-natvis:
name: 'Build natvis'
strategy:
Expand Down
167 changes: 167 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# This CMake build file is intended for use with the llvm-mingw toolchain:
# https://github.com/mstorsjo/llvm-mingw
#
# It most probably doesn't work with MSVC.

cmake_minimum_required(VERSION 3.12)

project(cppwinrt LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

set(CPPWINRT_BUILD_VERSION "2.3.4.5" CACHE STRING "The version string used for cppwinrt.")
add_compile_definitions(CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}")

# WinMD uses CreateFile2 which requires Windows 8.
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_include_directories(prebuild PRIVATE cppwinrt/)


# === Step to create autogenerated files ===

file(GLOB PREBUILD_STRINGS_FILES
LIST_DIRECTORIES false
CONFIGURE_DEPENDS
strings/*.h
)
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}"
DEPENDS
prebuild
${PREBUILD_STRINGS_FILES}
VERBATIM
)


# === cppwinrt ===

set(CPPWINRT_SRCS
cppwinrt/main.cpp
"${PROJECT_BINARY_DIR}/strings.cpp"
)

set(CPPWINRT_HEADERS
cppwinrt/pch.h
cppwinrt/cmd_reader.h
cppwinrt/code_writers.h
cppwinrt/component_writers.h
cppwinrt/file_writers.h
cppwinrt/helpers.h
cppwinrt/pch.h
cppwinrt/settings.h
cppwinrt/task_group.h
cppwinrt/text_writer.h
cppwinrt/type_writers.h
)

add_custom_command(
OUTPUT
"${PROJECT_BINARY_DIR}/app.manifest"
COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest" "${PROJECT_BINARY_DIR}/app.manifest"
DEPENDS "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest"
VERBATIM
)
# Do the configure_file dance so that app.manifest.rc don't get modified every
# single time the project is reconfigured and trigger a rebuild.
file(WRITE "${PROJECT_BINARY_DIR}/app.manifest.rc.in" "1 24 \"app.manifest\"\n")
configure_file(
"${PROJECT_BINARY_DIR}/app.manifest.rc.in"
"${PROJECT_BINARY_DIR}/app.manifest.rc"
COPYONLY
)

set(CPPWINRT_RESOURCES
"${PROJECT_BINARY_DIR}/app.manifest"
"${PROJECT_BINARY_DIR}/app.manifest.rc"
"${PROJECT_BINARY_DIR}/version.rc"
)

add_executable(cppwinrt ${CPPWINRT_SRCS} ${CPPWINRT_RESOURCES} ${CPPWINRT_HEADERS})
target_include_directories(cppwinrt PRIVATE ${PROJECT_BINARY_DIR})
target_link_libraries(cppwinrt shlwapi)


# HACK: Handle the xmllite import lib.
# mingw-w64 before commit 5ac1a2c is missing the import lib for xmllite. This
# checks whether the current build environment provides libxmllite.a, and
# generates the import lib if needed.

set(XMLLITE_LIBRARY xmllite)
if(MINGW)
function(TestLinkXmlLite OUTPUT_VARNAME)
include(CheckCXXSourceCompiles)
set(CMAKE_REQUIRED_LIBRARIES xmllite)
check_cxx_source_compiles("
#include <xmllite.h>
int main() {
CreateXmlReader(__uuidof(IXmlReader), nullptr, nullptr);
}
" ${OUTPUT_VARNAME})
endfunction()

function(TestIsI386 OUTPUT_VARNAME)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#if !defined(__i386__) && !defined(_M_IX86)
# error Not i386
#endif
int main() {}
" ${OUTPUT_VARNAME})
endfunction()

TestLinkXmlLite(HAS_LIBXMLLITE)
if(NOT HAS_LIBXMLLITE)
TestIsI386(TARGET_IS_I386)
if(TARGET_IS_I386)
set(XMLLITE_DEF_FILE xmllite_i386)
else()
set(XMLLITE_DEF_FILE xmllite)
endif()
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"
DEPENDS "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def"
VERBATIM
)
add_custom_target(gen-libxmllite
DEPENDS "${PROJECT_BINARY_DIR}/libxmllite.a"
)
set(XMLLITE_LIBRARY "${PROJECT_BINARY_DIR}/libxmllite.a")
add_dependencies(cppwinrt gen-libxmllite)
endif()
endif()
target_link_libraries(cppwinrt "${XMLLITE_LIBRARY}")


# === winmd: External header-only library for reading winmd files ===

include(ExternalProject)
ExternalProject_Add(winmd
URL https://github.com/microsoft/winmd/releases/download/1.0.210629.2/Microsoft.Windows.WinMD.1.0.210629.2.nupkg
URL_HASH SHA256=4c5f29d948f5b3d724d229664c8f8e4823250d3c9f23ad8067b732fc7076d8c7
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
add_dependencies(cppwinrt winmd)
ExternalProject_Get_Property(winmd SOURCE_DIR)
set(winmd_SOURCE_DIR "${SOURCE_DIR}")
target_include_directories(cppwinrt PRIVATE "${winmd_SOURCE_DIR}")


include(CTest)
add_subdirectory(test)
13 changes: 13 additions & 0 deletions mingw-support/xmllite.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are very simple def files. I'm not sure what value it provides to have them generated by a tool and what licensing issues may occur as a result. Can we remove the comments?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if it'd be possible to update to a newer snapshot of mingw-w64 (unfortunately I don't have an actual release of my toolchains that includes it) this wouldn't be needed iirc.

Other than that, removing the comment should surely be fine.

; Definition file of XmlLite.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "XmlLite.dll"
EXPORTS
CreateXmlReader
CreateXmlReaderInputWithEncodingCodePage
CreateXmlReaderInputWithEncodingName
CreateXmlWriter
CreateXmlWriterOutputWithEncodingCodePage
CreateXmlWriterOutputWithEncodingName
13 changes: 13 additions & 0 deletions mingw-support/xmllite_i386.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
;
; Definition file of XmlLite.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "XmlLite.dll"
EXPORTS
CreateXmlReader@12
CreateXmlReaderInputWithEncodingCodePage@24
CreateXmlReaderInputWithEncodingName@24
CreateXmlWriter@12
CreateXmlWriterOutputWithEncodingCodePage@16
CreateXmlWriterOutputWithEncodingName@16
40 changes: 40 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# The tests use newer C++ features.
set(CMAKE_CXX_STANDARD 20)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")

include_directories("${CMAKE_CURRENT_SOURCE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}/cppwinrt")
include_directories("${CMAKE_CURRENT_BINARY_DIR}/cppwinrt")

function(TestIsX64 OUTPUT_VARNAME)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#if !defined(__x86_64__) && !defined(_M_X64)
# error Not x86_64
#endif
int main() {}
" ${OUTPUT_VARNAME})
endfunction()
TestIsX64(TARGET_IS_X64)
if(TARGET_IS_X64)
add_compile_options(-mcx16)
endif()


add_custom_command(
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h"
COMMAND "${PROJECT_BINARY_DIR}/cppwinrt" -input local -output "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt" -verbose
DEPENDS
cppwinrt
VERBATIM
)
add_custom_target(build-cppwinrt-projection
DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h"
)


add_subdirectory(test)
add_subdirectory(test_win7)
13 changes: 13 additions & 0 deletions test/mingw_com_support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#if defined(__clang__)
#define HAS_DECLSPEC_UUID __has_declspec_attribute(uuid)
#elif defined(_MSC_VER)
#define HAS_DECLSPEC_UUID 1
#else
#define HAS_DECLSPEC_UUID 0
#endif

#if HAS_DECLSPEC_UUID
#define DECLSPEC_UUID(x) __declspec(uuid(x))
#else
#define DECLSPEC_UUID(x)
#endif
71 changes: 71 additions & 0 deletions test/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
file(GLOB TEST_SRCS
LIST_DIRECTORIES false
CONFIGURE_DEPENDS
*.cpp
)
list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp")


# We can't build test_component[*] for mingw-w64 because it doesn't have an
# alternative to midl that can produce winmd files. Also, even if we do manage
# to reuse the MSVC-compiled binaries, mingw-w64 is still missing
# windowsnumerics.impl.h which is needed to provide the types
Comment on lines +10 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Clang builds depend on the Windows SDK, just like MSVC. I take it mingw doesn't?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They have their own equivalent headers due to the Windows SDK license not allowing redistribution, and the SDK headers depending on too many MSVC-isms

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also important to distinguish key aspect here: Clang can target both MSVC ABI (using Windows SDK) and GCC ABI (using mingw-w64).

# winrt::Windows::Foundation::Numerics::float2 and friends that the components
# use.
list(APPEND BROKEN_TESTS
agility
delegates
enum
event_deferral
in_params
in_params_abi
no_make_detection
noexcept
optional
out_params
out_params_abi
parent_includes
rational
return_params
return_params_abi
struct_delegate
structs
uniform_in_params
velocity
)

list(APPEND BROKEN_TESTS
# depends on pplawait.h
when
)

# Exclude broken tests
foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS)
list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp")
endforeach()

add_executable(test-vanilla main.cpp ${TEST_SRCS})
set_target_properties(test-vanilla PROPERTIES OUTPUT_NAME "test")
target_link_libraries(test-vanilla runtimeobject)

target_precompile_headers(test-vanilla PRIVATE pch.h)
set_source_files_properties(
main.cpp
coro_foundation.cpp
coro_system.cpp
coro_threadpool.cpp
coro_uicore.cpp
custom_activation.cpp
generic_type_names.cpp
guid_include.cpp
inspectable_interop.cpp
module_lock_dll.cpp
PROPERTIES SKIP_PRECOMPILE_HEADERS true
)

add_dependencies(test-vanilla build-cppwinrt-projection)

add_test(
NAME test
COMMAND "$<TARGET_FILE:test-vanilla>"
)
2 changes: 1 addition & 1 deletion test/test/async_auto_cancel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ namespace
}
}

#if defined(__clang__)
#if defined(__clang__) && defined(_MSC_VER)
// FIXME: Test is known to segfault when built with Clang.
TEST_CASE("async_auto_cancel", "[.clang-crash]")
#else
Expand Down
2 changes: 1 addition & 1 deletion test/test/async_cancel_callback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ namespace
}
}

#if defined(__clang__)
#if defined(__clang__) && defined(_MSC_VER)
// FIXME: Test is known to segfault when built with Clang.
TEST_CASE("async_cancel_callback", "[.clang-crash]")
#else
Expand Down
Loading