Skip to content

build: add CMake based build system for XCTest #214

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 1 commit into from
Jun 11, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
122 changes: 122 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@

Copy link
Contributor

Choose a reason for hiding this comment

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

Tiny nit-pick/question: is there a reason you're leaving an empty line at the top of the CMake files? Same goes for the cmake/modules/SwiftSupport.cmake file below.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, ideally, someone would do the hard work of figuring out how to add the authorship information to the CMake content. I've been lazy and this is something that should be done at some point - it is not for any functional reason, only so that there is uniformity in all the files across the repositories.

cmake_minimum_required(VERSION 3.4.3)

list(APPEND CMAKE_MODULE_PATH
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")

project(XCTest
LANGUAGES
C)

option(XCTEST_PATH_TO_LIBDISPATCH_SOURCE "Path to libdispatch source" "")
option(XCTEST_PATH_TO_LIBDISPATCH_BUILD "Path to libdispatch build" "")

option(XCTEST_PATH_TO_FOUNDATION_BUILD "Path to Foundation build" "")

option(XCTEST_PATH_TO_COREFOUNDATION_BUILD "Path to CoreFoundation build" "")

find_package(LLVM CONFIG)
if(NOT LLVM_FOUND)
message(SEND_ERROR "Could not find LLVM; configure with -DCMAKE_PREFIX_PATH=/path/to/llvm/install")
Copy link
Contributor

Choose a reason for hiding this comment

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

Question for you: my understanding is that there's also a method of configuration in which the llvm-config executable is invoked, is that correct? But I believe I heard that means of configuration is deprecated -- I'm not sure. Do you know the current situation is?

To be clear, I'm not asking you to change anything here, this looks right to me, I'm just wondering about llvm-config.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is the more modern, CMake way to handle this. LLVM will install a CMake module that can be used. If you use the llvm-config invocation approach, that requires the user to specify the path to the installation. If you install LLVM to the system normally, this should JustWork(TM) so it is nicer.

endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")

include(${LLVM_DIR}/LLVMConfig.cmake)

list(APPEND CMAKE_MODULE_PATH ${LLVM_DIR})
include(AddLLVM)

include(SwiftSupport)
include(GNUInstallDirs)

set(swift_optimization_flags)
if(CMAKE_BUILD_TYPE MATCHES Release)
set(swift_optimization_flags -O)
endif()

add_swift_library(XCTest
MODULE_NAME
XCTest
MODULE_LINK_NAME
XCTest
MODULE_PATH
${CMAKE_CURRENT_BINARY_DIR}/swift/XCTest.swiftmodule
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}XCTest${CMAKE_SHARED_LIBRARY_SUFFIX}
LINK_FLAGS
-L${XCTEST_PATH_TO_LIBDISPATCH_BUILD}/src -ldispatch
-L${XCTEST_PATH_TO_FOUNDATION_BUILD} -lFoundation
SOURCES
Sources/XCTest/Private/WallClockTimeMetric.swift
Sources/XCTest/Private/TestListing.swift
Sources/XCTest/Private/XCTestCaseSuite.swift
Sources/XCTest/Private/TestFiltering.swift
Sources/XCTest/Private/XCTestInternalObservation.swift
Sources/XCTest/Private/ObjectWrapper.swift
Sources/XCTest/Private/PerformanceMeter.swift
Sources/XCTest/Private/PrintObserver.swift
Sources/XCTest/Private/ArgumentParser.swift
Sources/XCTest/Private/XCPredicateExpectation.swift
Sources/XCTest/Public/XCTestRun.swift
Sources/XCTest/Public/XCTestMain.swift
Sources/XCTest/Public/XCTestCase.swift
Sources/XCTest/Public/XCTestSuite.swift
Sources/XCTest/Public/XCTestSuiteRun.swift
Sources/XCTest/Public/XCTestErrors.swift
Sources/XCTest/Public/XCTestObservation.swift
Sources/XCTest/Public/XCTestCaseRun.swift
Sources/XCTest/Public/XCAbstractTest.swift
Sources/XCTest/Public/XCTestObservationCenter.swift
Sources/XCTest/Public/XCTestCase+Performance.swift
Sources/XCTest/Public/XCTAssert.swift
Sources/XCTest/Public/Asynchronous/XCTestCase+NotificationExpectation.swift
Sources/XCTest/Public/Asynchronous/XCTestCase+PredicateExpectation.swift
Sources/XCTest/Public/Asynchronous/XCPredicateExpectationHandler.swift
Sources/XCTest/Public/Asynchronous/XCWaitCompletionHandler.swift
Sources/XCTest/Public/Asynchronous/XCNotificationExpectationHandler.swift
Sources/XCTest/Public/Asynchronous/XCTestCase+Asynchronous.swift
Sources/XCTest/Public/Asynchronous/XCTestExpectation.swift
Copy link
Contributor

Choose a reason for hiding this comment

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

(I vaguely remembered that globbing source files in CMake was discouraged, so for any other reviewers out there, I looked up the exact reason: https://stackoverflow.com/a/32412044/679254)

SWIFT_FLAGS
${swift_optimization_flags}

-I${XCTEST_PATH_TO_LIBDISPATCH_SOURCE}
-I${XCTEST_PATH_TO_LIBDISPATCH_BUILD}/src/swift
-Xcc -fblocks

-I${XCTEST_PATH_TO_FOUNDATION_BUILD}/swift
-Fsystem ${XCTEST_PATH_TO_COREFOUNDATION_BUILD}/System/Library/Frameworks)

if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
set(LIT_COMMAND "${PYTHON_EXECUTABLE};${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py"
CACHE STRING "command used to spawn llvm-lit")
else()
find_program(LIT_COMMAND NAMES llvm-lit lit.py lit)
endif()
add_custom_target(check-xctest
COMMAND
${CMAKE_COMMAND} -E env
BUILT_PRODUCTS_DIR=${CMAKE_BINARY_DIR}
CORE_FOUNDATION_BUILT_PRODUCTS_DIR=${XCTEST_PATH_TO_COREFOUNDATION_BUILD}
FOUNDATION_BUILT_PRODUCTS_DIR=${XCTEST_PATH_TO_FOUNDATION_BUILD}
LIBDISPATCH_SRC_DIR=${XCTEST_PATH_TO_LIBDISPATCH_SOURCE}
LIBDISPATCH_BUILD_DIR=${XCTEST_PATH_TO_LIBDISPATCH_BUILD}
LIBDISPATCH_OVERLAY_DIR=${XCTEST_PATH_TO_LIBDISPATCH_BUILD}/swift
SWIFT_EXEC=${CMAKE_SWIFT_COMPILER}
${LIT_COMMAND} -sv ${CMAKE_SOURCE_DIR}/Tests/Functional
COMMENT
"Running XCTest functional test suite"
DEPENDS
XCTest
USES_TERMINAL)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/swift/XCTest.swiftdoc
${CMAKE_CURRENT_BINARY_DIR}/swift/XCTest.swiftmodule
DESTINATION
${CMAKE_INSTALL_FULL_LIBDIR}/swift/${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR})
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}XCTest${CMAKE_SHARED_LIBRARY_SUFFIX}
DESTINATION
${CMAKE_INSTALL_FULL_LIBDIR})

4 changes: 4 additions & 0 deletions Tests/Functional/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ swift_exec = [
'-Xlinker', built_products_dir,
'-L', built_products_dir,
'-I', built_products_dir,
'-I', os.path.join(built_products_dir, 'swift'),
]

if platform.system() == 'Darwin':
Expand Down Expand Up @@ -76,7 +77,9 @@ else:
'-Xlinker', foundation_dir,
'-L', foundation_dir,
'-I', foundation_dir,
'-I', os.path.join(foundation_dir, 'swift'),
'-I', core_foundation_dir,
'-F', os.path.join(core_foundation_dir, 'System', 'Library', 'Frameworks'),
])
config.environment['LD_LIBRARY_PATH'] = foundation_dir
# We also need to link swift-corelibs-libdispatch, if
Expand All @@ -92,6 +95,7 @@ else:
'-I', libdispatch_src_dir,
'-I', libdispatch_overlay_dir,
'-L', libdispatch_build_dir,
'-L', os.path.join(libdispatch_build_dir, 'src'),
])

# Having prepared the swiftc command, we set the substitution.
Expand Down
133 changes: 133 additions & 0 deletions cmake/modules/SwiftSupport.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@

include(CMakeParseArguments)

function(add_swift_target target)
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a handy, generic function. Are you anticipating moving it somewhere where all the swift-corelibs-* projects could use it, maybe someday?

Copy link

Choose a reason for hiding this comment

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

swift-tools-support-core repository is not ready yet but it can be used to hold the shared infrastructure once its open for business!

Copy link
Member Author

Choose a reason for hiding this comment

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

@modocache - you are right, this is a handy, generic function. I use the same basic functionality in swift-corelibs-libdispatch and am using it in swift-corelibs-foundation too. Once we have the shared repository, moving this would be great.

set(options LIBRARY)
set(single_value_options MODULE_NAME;MODULE_LINK_NAME;MODULE_PATH;MODULE_CACHE_PATH;OUTPUT;TARGET)
set(multiple_value_options CFLAGS;DEPENDS;LINK_FLAGS;SOURCES;SWIFT_FLAGS)

cmake_parse_arguments(AST "${options}" "${single_value_options}" "${multiple_value_options}" ${ARGN})

set(flags ${CMAKE_SWIFT_FLAGS})
set(link_flags)

if(AST_TARGET)
list(APPEND flags -target;${AST_TARGET})
endif()
if(AST_MODULE_NAME)
list(APPEND flags -module-name;${AST_MODULE_NAME})
else()
list(APPEND flags -module-name;${target})
endif()
if(AST_MODULE_LINK_NAME)
list(APPEND flags -module-link-name;${AST_MODULE_LINK_NAME})
endif()
if(AST_MODULE_CACHE_PATH)
list(APPEND flags -module-cache-path;${AST_MODULE_CACHE_PATH})
endif()
if(AST_SWIFT_FLAGS)
foreach(flag ${AST_SWIFT_FLAGS})
list(APPEND flags ${flag})
endforeach()
endif()
if(AST_CFLAGS)
foreach(flag ${AST_CFLAGS})
list(APPEND flags -Xcc;${flag})
endforeach()
endif()
if(AST_LINK_FLAGS)
foreach(flag ${AST_LINK_FLAGS})
list(APPEND link_flags ${flag})
endforeach()
endif()
if(NOT AST_OUTPUT)
if(AST_LIBRARY)
set(AST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}.dir/${CMAKE_SHARED_LIBRARY_PREFIX}${target}${CMAKE_SHARED_LIBRARY_SUFFIX})
else()
set(AST_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}.dir/${target}${CMAKE_EXECUTABLE_SUFFIX})
endif()
endif()

set(sources)
foreach(source ${AST_SOURCES})
get_filename_component(location ${source} PATH)
if(IS_ABSOLUTE ${location})
list(APPEND sources ${source})
else()
list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/${source})
endif()
endforeach()

set(objs)
set(mods)
set(docs)
set(i 0)
foreach(source ${sources})
get_filename_component(name ${source} NAME)

set(obj ${CMAKE_CURRENT_BINARY_DIR}/${target}.dir/${name}${CMAKE_C_OUTPUT_EXTENSION})
set(mod ${CMAKE_CURRENT_BINARY_DIR}/${target}.dir/${name}.swiftmodule~partial)
set(doc ${CMAKE_CURRENT_BINARY_DIR}/${target}.dir/${name}.swiftdoc~partial)

set(all_sources ${sources})
list(INSERT all_sources ${i} -primary-file)

add_custom_command(OUTPUT
${obj}
${mod}
${doc}
DEPENDS
${source}
COMMAND
${CMAKE_SWIFT_COMPILER} -frontend ${flags} -emit-module-path ${mod} -emit-module-doc-path ${doc} -o ${obj} -c ${all_sources})

list(APPEND objs ${obj})
list(APPEND mods ${mod})
list(APPEND docs ${doc})

math(EXPR i "${i}+1")
endforeach()

if(AST_LIBRARY)
get_filename_component(module_directory ${AST_MODULE_PATH} DIRECTORY)

set(module ${AST_MODULE_PATH})
set(documentation ${module_directory}/${AST_MODULE_NAME}.swiftdoc)

add_custom_command(OUTPUT
${module}
${documentation}
DEPENDS
${mods}
${docs}
COMMAND
${CMAKE_SWIFT_COMPILER} -frontend ${flags} -sil-merge-partial-modules -emit-module ${mods} -o ${module} -emit-module-doc-path ${documentation})
endif()

if(AST_LIBRARY)
set(emit_library -emit-library)
endif()
add_custom_command(OUTPUT
${AST_OUTPUT}
DEPENDS
${objs}
COMMAND
${CMAKE_SWIFT_COMPILER} ${emit_library} ${link_flags} -o ${AST_OUTPUT} ${objs}
COMMAND
${CMAKE_COMMAND} -E copy ${AST_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR})
add_custom_target(${target}
ALL
DEPENDS
${AST_OUTPUT}
${module}
${documentation})
endfunction()

function(add_swift_library library)
add_swift_target(${library} LIBRARY ${ARGN})
endfunction()

function(add_swift_executable executable)
add_swift_target(${executable} ${ARGN})
endfunction()