Skip to content
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

Swift binding integration #23

Merged
merged 6 commits into from Apr 25, 2016
@@ -16,6 +16,12 @@ endif()
include(CMakeParseArguments)
include(CheckCXXCompilerFlag)

# Get the SDK path for OSX.
execute_process(
COMMAND xcrun --sdk macosx --show-sdk-path
OUTPUT_VARIABLE CMAKE_OSX_SYSROOT
OUTPUT_STRIP_TRAILING_WHITESPACE)

project(llbuild)

# Add path for custom modules
@@ -62,6 +68,29 @@ set(LLBUILD_LIBRARY_OUTPUT_INTDIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR
find_package(Lit REQUIRED)
find_package(FileCheck REQUIRED)

# Fine swiftc on OSX using `xcrun --find swiftc` and `find_package` on Linux.
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
execute_process(
COMMAND xcrun --find swiftc
OUTPUT_VARIABLE SWIFTC_EXECUTABLE
OUTPUT_STRIP_TRAILING_WHITESPACE)
set(SWIFTC_FOUND TRUE)
else()
find_package(Swiftc QUIET)
endif()

# Check if we have correct swift version for bindings.
if (SWIFTC_FOUND)
execute_process(
COMMAND ${SWIFTC_EXECUTABLE} --version
OUTPUT_VARIABLE SWIFTC_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT SWIFTC_VERSION MATCHES "(.*)Swift version 3.0(.*)")
set(SWIFTC_EXECUTABLE)
set(SWIFTC_FOUND FALSE)
endif()
endif()

###
# Setup compiler and project build settings

@@ -0,0 +1,16 @@
# Usage: find_package(Swiftc)
#
# If successful the following variables will be defined
# SWIFTC_FOUND
# SWIFTC_EXECUTABLE

find_program(SWIFTC_EXECUTABLE
NAMES swiftc
DOC "Path to 'swiftc' executable")

This comment has been minimized.

Copy link
@ddunbar

ddunbar Apr 25, 2016

Member

We need to check and record the TOOLCHAINS and SDKROOT in use... if not, then what will happen when run as:

env TOOLCHAINS=swift cmake ...

is we will just find /usr/bin/swiftc as the swiftc, but if we run again with a different TOOLCHAINS variable it won't work. I'd prefer if the configure step would bake in the value for TOOLCHAINS, I think.

This comment has been minimized.

Copy link
@aciidb0mb3r

aciidb0mb3r Apr 25, 2016

Author Member

fixed this by finding swiftc by xcrun --find swiftc on darwin


# Handle REQUIRED and QUIET arguments, this will also set SWIFTC_FOUND to true
# if SWIFTC_EXECUTABLE exists.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Swiftc
"Failed to locate 'swiftc' executable"
SWIFTC_EXECUTABLE)
@@ -111,3 +111,98 @@ function(add_unittest test_suite test_name)

set_property(TARGET ${test_name} APPEND PROPERTY COMPILE_DEFINITIONS GTEST_HAS_RTTI=0)
endfunction()

# Compile swift sources to a dynamic framework.
# Usage:
# target # Target name
# name # Swift Module name
# deps # Target dependencies
# sources # List of sources
# additional_args # List of additional args to pass
function(add_swift_module target name deps sources additional_args)

set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY})

list(APPEND ARGS -module-name ${name})
list(APPEND ARGS -incremental -emit-dependencies -emit-module)
list(APPEND ARGS -emit-module-path ${name}.swiftmodule)

set(FILEMAP ${BUILD_DIR}/output-file-map.json)
set(OUTPUT_FILE_MAP ${FILEMAP})

# Remove old file and start writing new one.
file(REMOVE ${FILEMAP})
file(APPEND ${FILEMAP} "{\n")
foreach(source ${sources})
file(APPEND ${FILEMAP} "\"${CMAKE_CURRENT_SOURCE_DIR}/${source}\": {\n")
file(APPEND ${FILEMAP} "\"dependencies\": \"${BUILD_DIR}/${source}.d\",\n")
set(OBJECT ${BUILD_DIR}/${source}.o)
list(APPEND OUTPUTS ${OBJECT})
file(APPEND ${FILEMAP} "\"object\": \"${OBJECT}\",\n")
file(APPEND ${FILEMAP} "\"swiftmodule\": \"${BUILD_DIR}/${source}~partial.swiftmodule\",\n")
file(APPEND ${FILEMAP} "\"swift-dependencies\": \"${BUILD_DIR}/${source}.swiftdeps\"\n},\n")
endforeach()
file(APPEND ${FILEMAP} "\"\": {\n")
file(APPEND ${FILEMAP} "\"swift-dependencies\": \"${BUILD_DIR}/master.swiftdeps\"\n")
file(APPEND ${FILEMAP} "}\n")
file(APPEND ${FILEMAP} "}")

list(APPEND ARGS -output-file-map ${OUTPUT_FILE_MAP})
list(APPEND ARGS -parse-as-library)
list(APPEND ARGS -c)

foreach(source ${sources})
list(APPEND ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${source})
endforeach()

# FIXME: Find a better way to handle build types.
if (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
list(APPEND ARGS -g)
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
list(APPEND ARGS -Onone -g)
else()
list(APPEND ARGS -O -whole-module-optimization)
endif()

foreach(arg ${additional_args})
list(APPEND ARGS ${arg})
endforeach()

if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
list(APPEND ARGS -sdk ${CMAKE_OSX_SYSROOT})
endif()

# Compile swiftmodule.
add_custom_command(
OUTPUT ${OUTPUTS}
COMMAND swiftc
ARGS ${ARGS}
DEPENDS ${sources}
)

# Link and create dynamic framework.
set(DYLIB_OUTPUT ${LLBUILD_LIBRARY_OUTPUT_INTDIR}/${target}.dylib)

if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
list(APPEND DYLYB_ARGS -sdk ${CMAKE_OSX_SYSROOT})
endif()

list(APPEND DYLYB_ARGS -module-name ${name})
list(APPEND DYLYB_ARGS -o ${DYLIB_OUTPUT})
list(APPEND DYLYB_ARGS -emit-library ${OUTPUTS})
foreach(arg ${additional_args})
list(APPEND DYLYB_ARGS ${arg})
endforeach()
list(APPEND DYLYB_ARGS -L ${LLBUILD_LIBRARY_OUTPUT_INTDIR})

add_custom_command(
OUTPUT ${DYLIB_OUTPUT}
COMMAND swiftc
ARGS ${DYLYB_ARGS}
DEPENDS ${OUTPUTS}
)

# Add the target.
add_custom_target(${target} ALL DEPENDS ${deps} ${DYLIB_OUTPUT} ${sources})
endfunction()
@@ -0,0 +1,93 @@
import llbuild

typealias Compute = [Int] -> Int

class SimpleTask: Task {
let inputs: [Key]
var values: [Int]
let compute: Compute

init(_ inputs: [Key], compute: Compute) {
self.inputs = inputs
values = [Int](repeating: 0, count: inputs.count)
self.compute = compute
}

func start(_ engine: TaskBuildEngine) {
for (idx, input) in inputs.enumerated() {
engine.taskNeedsInput(input, inputID: idx)
}
}

func provideValue(_ engine: TaskBuildEngine, inputID: Int, value: Value) {
values[inputID] = Int(value.toString())!
}

func inputsAvailable(_ engine: TaskBuildEngine) {
let result = compute(values)
engine.taskIsComplete(Value("\(result)"), forceChange: false)
}
}

class SimpleBuildEngineDelegate: BuildEngineDelegate {
var builtKeys = [Key]()

func lookupRule(_ key: Key) -> Rule {
switch key.toString() {
case "A":
return SimpleRule([]) { arr in
precondition(self.builtKeys.isEmpty)
self.builtKeys.append(key)
return 2
}
case "B":
return SimpleRule([]) { arr in
precondition(self.builtKeys.count == 1)
self.builtKeys.append(key)
return 3
}
case "C":
return SimpleRule([Key("A"), Key("B")]) { arr in
precondition(self.builtKeys.count == 2)
precondition(self.builtKeys[0].toString() == "A")
precondition(self.builtKeys[1].toString() == "B")
self.builtKeys.append(key)
return arr[0] * arr[1]
}
default: fatalError("Unexpected key \(key) lookup")
}
}
}

class SimpleRule: Rule {
let inputs: [Key]
let compute: Compute
init(_ inputs: [Key], compute: Compute) {
self.inputs = inputs
self.compute = compute
}
func createTask() -> Task {
return SimpleTask(inputs, compute: compute)
}
}

let delegate = SimpleBuildEngineDelegate()
var engine = BuildEngine(delegate: delegate)

// C depends on A and B
var result = engine.build(key: Key("C"))
print("\(result.toString())")

precondition(result.toString() == "6")

// Make sure building already built keys do not re-compute.
delegate.builtKeys.removeAll()
precondition(delegate.builtKeys.isEmpty)

result = engine.build(key: Key("A"))
precondition(result.toString() == "2")
precondition(delegate.builtKeys.isEmpty)

result = engine.build(key: Key("B"))
precondition(result.toString() == "3")
precondition(delegate.builtKeys.isEmpty)
@@ -1,2 +1,11 @@
add_custom_target(swift-bindings
DEPENDS libllbuild)
# Set sources.
set(SOURCES llbuild.swift)

# Link C API.
list(APPEND additional_args -import-underlying-module -lllbuild)
list(APPEND additional_args -I ${CMAKE_CURRENT_SOURCE_DIR}/../libllbuild/public-api)

# Add swift bindings target if swift compiler is present.
if (SWIFTC_FOUND)
add_swift_module(swift-bindings llbuild libllbuild "${SOURCES}" "${additional_args}")
endif()
@@ -9,7 +9,6 @@
// This file contains Swift bindings for the llbuild C API.
import Foundation
import llbuild

enum DatabaseError: ErrorProtocol {
case AttachFailure(message: String)
@@ -33,7 +33,7 @@ if(PYTHONINTERP_FOUND)
--param build_mode=${build_mode})

set(test_target_dependencies
llbuild libllbuild swift-build-tool UnitTests)
llbuild libllbuild swift-bindings swift-build-tool UnitTests)

add_custom_target(test-llbuild
COMMAND ${lit_command} ${CMAKE_CURRENT_BINARY_DIR}
@@ -1 +1 @@
config.suffixes = ['.llbuild']
config.suffixes = ['.txt', '.llbuild']
@@ -0,0 +1,8 @@
# Check basic 'core' functionality of the swift bindings
#
# REQUIRES: has-swift=TRUE
# RUN: env LD_LIBRARY_PATH=%{llbuild-lib-dir} %{swiftc} %{swiftc-platform-flags} %{srcroot}/examples/swift-bindings/core/basic.swift -I %{srcroot}/build/products/swift-bindings -I %{srcroot}/products/libllbuild/public-api -Xlinker %{llbuild-lib-dir}/swift-bindings.dylib -o %t.exe
# RUN: env LD_LIBRARY_PATH=%{llbuild-lib-dir} %t.exe %s > %t.out
# RUN: cat %t.out
# RUN: %{FileCheck} %s --input-file %t.out
# CHECK: 6
@@ -64,6 +64,9 @@ config.target_triple = None
# Add a platform feature.
config.available_features.add("platform="+platform.system())

# Add swiftc feature.
config.available_features.add("has-swift="+config.swiftc_found)

###

# Define our supported substitutions.
@@ -72,8 +75,10 @@ config.substitutions.append( ('%{llbuild}', "%r" % (
config.substitutions.append( ('%{swift-build-tool}', "%r" % (
os.path.join(llbuild_tools_dir, 'swift-build-tool'),)) )
config.substitutions.append( ('%{FileCheck}', config.filecheck_path) )
config.substitutions.append( ('%{swiftc}', config.swiftc_path) )
config.substitutions.append( ('%{llbuild-lib-dir}', llbuild_lib_dir) )
config.substitutions.append( ('%{srcroot}', llbuild_src_root) )
config.substitutions.append( ('%{swiftc-platform-flags}', "" if not config.osx_sysroot else "-sdk " + config.osx_sysroot) )

###

@@ -12,6 +12,9 @@ config.llbuild_lib_dir = "@LLBUILD_LIBS_DIR@"

# Tools found by the build system.
config.filecheck_path = "@FILECHECK_EXECUTABLE@"
config.swiftc_path = "@SWIFTC_EXECUTABLE@"
config.swiftc_found = "@SWIFTC_FOUND@"
config.osx_sysroot = "@CMAKE_OSX_SYSROOT@"

# Support substitution of the tools_dir with user parameters. This is
# used when we can't determine the tool dir at configuration time.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.