swift: add iOS simulator support

updates tailscale/tailscale#15802

This adds the required targets to build for the iOS
simulator.   We support both ios, ios-sim, and ios-fat
framework targets.

The sample app is updated to link in the ios-fat version
so it can be run on any target device or sim.
This commit is contained in:
Jonathan Nobels
2025-05-21 12:56:49 -04:00
committed by Jonathan Nobels
parent 78294ac1d6
commit 727bd68619
13 changed files with 455 additions and 54 deletions

4
.gitignore vendored
View File

@@ -2,8 +2,8 @@ libtailscale.so
libtailscale.a
libtailscale.h
libtailscale.tar*
libtailscale_ios.a
libtailscale_ios.h
libtailscale_*.a
libtailscale_*.h
/tstestcontrol/libtstestcontrol.a
/tstestcontrol/libtstestcontrol.h

View File

@@ -6,11 +6,21 @@ libtailscale.a:
go build -buildmode=c-archive
libtailscale_ios.a:
GOOS=ios GOARCH=arm64 CGO_ENABLED=1 CC=$(PWD)/swift/script/clangwrap.sh go build -v -ldflags -w -tags ios -o libtailscale_ios.a -buildmode=c-archive
GOOS=ios GOARCH=arm64 CGO_ENABLED=1 CC=$(PWD)/swift/script/clangwrap-ios.sh go build -v -ldflags -w -tags ios -o libtailscale_ios.a -buildmode=c-archive
libtailscale_ios_sim_arm64.a:
GOOS=ios GOARCH=arm64 CGO_ENABLED=1 CC=$(PWD)/swift/script/clangwrap-ios-sim-arm.sh go build -v -ldflags -w -tags ios -o libtailscale_ios_sim_arm64.a -buildmode=c-archive
libtailscale_ios_sim_x86_64.a:
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC=$(PWD)/swift/script/clangwrap-ios-sim-x86.sh go build -v -ldflags -w -tags ios -o libtailscale_ios_sim_x86_64.a -buildmode=c-archive
.PHONY: c-archive-ios
c-archive-ios: libtailscale_ios.a ## Builds libtailscale_ios.a for iOS (iOS SDK required)
.PHONY: c-archive-ios-sim
c-archive-ios-sim: libtailscale_ios_sim_arm64.a libtailscale_ios_sim_x86_64.a ## Builds a fat binary for iOS (iOS SDK required)
lipo -create -output libtailscale_ios_sim.a libtailscale_ios_sim_x86_64.a libtailscale_ios_sim_arm64.a
.PHONY: c-archive
c-archive: libtailscale.a ## Builds libtailscale.a for the target platform
@@ -20,10 +30,8 @@ shared: ## Builds libtailscale.so for the target platform
.PHONY: clean
clean: ## Clean up build artifacts
rm -f libtailscale.a
rm -f libtailscale_ios.a
rm -f libtailscale.h
rm -f libtailscale_ios.h
rm -f libtailscale*.h
rm -f libtailscale*.a
.PHONY: help
help: ## Show this help

View File

@@ -2,13 +2,17 @@
## Instructions
First build TailscaleKit:
First build TailscaleKit for the platform you wish to target:
From /swift:
```
$ make macos
$ make ios-fat
```
The ios target expects the universal xcframework produced by make ios-fat and
can be run on either a device or the simulator.
In TailnetSettings, configure an auth key and a server/service to query.
```

View File

@@ -9,8 +9,8 @@
/* Begin PBXBuildFile section */
C25260032D7A71E800BD3CCA /* TailscaleKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2525FC52D7A69DE00BD3CCA /* TailscaleKit.framework */; };
C25260052D7A71FE00BD3CCA /* TailscaleKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2525FC52D7A69DE00BD3CCA /* TailscaleKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
C289804A2DBAA8DA0019B7EB /* TailscaleKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C28980492DBAA7E50019B7EB /* TailscaleKit.framework */; };
C289804B2DBAA8DA0019B7EB /* TailscaleKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C28980492DBAA7E50019B7EB /* TailscaleKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
C2CE237E2DD7756B0096C105 /* TailscaleKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CE23762DD76A5C0096C105 /* TailscaleKit.framework */; };
C2ED636C2DDE3C1400297161 /* TailscaleKit.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C2ED636B2DDE3C1400297161 /* TailscaleKit.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -30,7 +30,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
C289804B2DBAA8DA0019B7EB /* TailscaleKit.framework in Embed Frameworks */,
C2ED636C2DDE3C1400297161 /* TailscaleKit.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -43,16 +43,11 @@
C25260082D7A7DC400BD3CCA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
C289803E2DBA8A350019B7EB /* HelloFromTailscale_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloFromTailscale_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; };
C28980492DBAA7E50019B7EB /* TailscaleKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TailscaleKit.framework; path = "../../build/Build/Products/Release-iphoneos/TailscaleKit.framework"; sourceTree = "<group>"; };
C2CE23762DD76A5C0096C105 /* TailscaleKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TailscaleKit.framework; path = "../../build/Build/Products/Release-iphonesimulator/TailscaleKit.framework"; sourceTree = "<group>"; };
C2ED636B2DDE3C1400297161 /* TailscaleKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = TailscaleKit.xcframework; path = "../../build/Build/Products/Release-iphonefat/TailscaleKit.xcframework"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
C25260072D7A7BAE00BD3CCA /* Exceptions for "HelloFromTailscale" folder in "HelloFromTailscale" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = C2525FF02D7A70B700BD3CCA /* HelloFromTailscale */;
};
C289803F2DBA8A360019B7EB /* Exceptions for "HelloFromTailscale" folder in "HelloFromTailscale_iOS" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
@@ -62,13 +57,20 @@
);
target = C28980342DBA8A350019B7EB /* HelloFromTailscale_iOS */;
};
C2CE23752DD76A330096C105 /* Exceptions for "HelloFromTailscale" folder in "HelloFromTailscale" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info_iOS.plist,
);
target = C2525FF02D7A70B700BD3CCA /* HelloFromTailscale */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
C2525FF22D7A70B700BD3CCA /* HelloFromTailscale */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
C25260072D7A7BAE00BD3CCA /* Exceptions for "HelloFromTailscale" folder in "HelloFromTailscale" target */,
C2CE23752DD76A330096C105 /* Exceptions for "HelloFromTailscale" folder in "HelloFromTailscale" target */,
C289803F2DBA8A360019B7EB /* Exceptions for "HelloFromTailscale" folder in "HelloFromTailscale_iOS" target */,
);
path = HelloFromTailscale;
@@ -89,7 +91,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C289804A2DBAA8DA0019B7EB /* TailscaleKit.framework in Frameworks */,
C2CE237E2DD7756B0096C105 /* TailscaleKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -118,6 +120,8 @@
C2525FC42D7A69DE00BD3CCA /* Frameworks */ = {
isa = PBXGroup;
children = (
C2ED636B2DDE3C1400297161 /* TailscaleKit.xcframework */,
C2CE23762DD76A5C0096C105 /* TailscaleKit.framework */,
C2525FC52D7A69DE00BD3CCA /* TailscaleKit.framework */,
C28980492DBAA7E50019B7EB /* TailscaleKit.framework */,
);
@@ -374,7 +378,7 @@
DEVELOPMENT_TEAM = W5364U7YZB;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "../../build/Build/**";
FRAMEWORK_SEARCH_PATHS = ../../build/Build;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = HelloFromTailscale/Info.plist;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -403,7 +407,7 @@
DEVELOPMENT_TEAM = W5364U7YZB;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "../../build/Build/**";
FRAMEWORK_SEARCH_PATHS = ../../build/Build;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = HelloFromTailscale/Info.plist;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -432,7 +436,7 @@
DEVELOPMENT_TEAM = W5364U7YZB;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "../../build/Build/Products/Release-iphoneOS";
FRAMEWORK_SEARCH_PATHS = "../../build/Build/Products/Release-iphonefat";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = HelloFromTailscale/Info_iOS.plist;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
@@ -467,7 +471,7 @@
DEVELOPMENT_TEAM = W5364U7YZB;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "../../build/Build/Products/Release-iphoneOS";
FRAMEWORK_SEARCH_PATHS = "../../build/Build/Products/Release-iphonefat";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = HelloFromTailscale/Info_iOS.plist;
INFOPLIST_KEY_NSHumanReadableCopyright = "";

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C2CE22D62DD680A20096C105"
BuildableName = "HelloFromTailscale_iOS_Simulator.app"
BlueprintName = "HelloFromTailscale_iOS_Simulator"
ReferencedContainer = "container:TailscaleKitHello.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C2CE22D62DD680A20096C105"
BuildableName = "HelloFromTailscale_iOS_Simulator.app"
BlueprintName = "HelloFromTailscale_iOS_Simulator"
ReferencedContainer = "container:TailscaleKitHello.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C2CE22D62DD680A20096C105"
BuildableName = "HelloFromTailscale_iOS_Simulator.app"
BlueprintName = "HelloFromTailscale_iOS_Simulator"
ReferencedContainer = "container:TailscaleKitHello.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -11,12 +11,12 @@ endif
# the libtailscale.a and libtailscale_ios.a dependencies.
.PHONY: all
all: test ios macos ## Runs the tests and builds all library targets
all: test ios macos ios-fat ## Runs the tests and builds all library targets
.PHONY: macos
macos: ## Builds TailscaleKit for macos to swift/build/Build/Products/Release (unsigned)
@echo
@echo "::: Building TailscaleKit for macOS :::"
@echo "::: Building TailscaleKit.framework for macOS :::"
cd .. && make c-archive
mkdir -p build
xcodebuild build -scheme "TailscaleKit (macOS)" \
@@ -26,9 +26,9 @@ macos: ## Builds TailscaleKit for macos to swift/build/Build/Products/Release (
CODE_SIGNING_ALLOWED=NO | $(XCPRETTIFIER)
.PHONY: ios
ios: ## Builds TailscaleKit for iOS to swift/build/Build/Products/Release (unsigned)
ios: ## Builds TailscaleKit for iOS to swift/build/Build/Products/Release-iphoneos (unsigned)
@echo
@echo "::: Building TailscaleKit for iOS :::"
@echo "::: Building TailscaleKit.framework for iOS :::"
cd .. && make c-archive-ios
mkdir -p build
xcodebuild build -scheme "TailscaleKit (iOS)" \
@@ -37,6 +37,27 @@ ios: ## Builds TailscaleKit for iOS to swift/build/Build/Products/Release (unsi
-destination 'generic/platform=iOS' \
CODE_SIGNING_ALLOWED=NO | $(XCPRETTIFIER)
.PHONY: ios-sim
ios-sim: ## Builds TailscaleKit for iOS to swift/build/Build/Products/Release-iphonesimulator (unsigned)
@echo
@echo "::: Building TailscaleKit.framework for iOS Simulator :::"
cd .. && make c-archive-ios-sim
mkdir -p build
xcodebuild build -scheme "TailscaleKit (Simulator)" \
-derivedDataPath build \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
CODE_SIGNING_ALLOWED=NO | $(XCPRETTIFIER)
.PHONY: ios-fat
ios-fat: ios-sim ios ## Builds TailscaleKit.xcframework to swift/build/Build/Products/Release-iphonefat
@echo
@echo "::: Building TailscaleKit.xcframework for ios and ios-simulator :::"
mkdir -p ./build/Build/Products/Release-iphonefat
xcodebuild -create-xcframework \
-framework ./build/Build/Products/Release-iphoneos/TailscaleKit.framework \
-framework ./build/Build/Products/Release-iphonesimulator/TailscaleKit.framework \
-output ./build/Build/Products/Release-iphonefat/TailscaleKit.xcframework
.PHONY: test
test: ## Run tests (macOS)

View File

@@ -14,38 +14,46 @@ Build Requirements:
Building Tailscale.framework:
First build the libtailscale dependecies:
From /swift
```
```bash
$ make macos
# make ios
$ make ios
$ make ios-sim
$ make ios-fat
```
Will build TailscaleKit.framework into /swift/build/Build/Products.
These recipes build different variants of TailscaleKit.framework into /swift/build/Build/Products.
Separate frameworks will be built for macOS and iOS. All dependencies (libtailscale.a)
Separate frameworks will be built for macOS and iOS and the iOS Simulator. All dependencies (libtailscale*.a)
are built automatically. Swift 6 is supported.
The ios and ios-sim frameworks are purposefully separated. The former is free of any simulator segments
and is suitable for app-store submissions. The latter is suitable for embedding when you
wish to run on a simulator in dev though 'make ios-fat' will produce an xcframework bundle including
both simulator and device frameworks for development.
The frameworks are not signed and must be signed when they are embedded.
Alternatively, you may build from xCode using the Tailscale scheme but the
libraries must be built first (since xCode will complain about paths and
permissions)
From /
```
To build only the static libraries, from /
```bash
$ make c-archive
$ make c-archive-ios
$ make c-archive-ios-sim
```
Non-apple builds are not supported (yet). We do use URLSession and Combine though
it is possible to purge both.
If you're writing pure C, or C++, link these and use the generated tailscale.h header.
make c-archive builds for the local machine architecture/platform (arm64 macOS from a mac)
Non-apple swift builds are not supported (yet) but should be possible with a little tweaking.
## Tests
From /swift
```
```bash
$ make test
```
@@ -53,16 +61,12 @@ $ make test
## Usage
Nodes need to be authorized in order to function. Set an auth key via
the config.authKey parameter, or watch the log stream and respond to the printed
authorization URL.
the config.authKey parameter, or watch the ipn bus (see the example) for
the browseToURL field for interactive web-based auth.
Here's a working example using an auth key:
```Swift
// Configures a Tailscale node and starts it up. The node here (and the key we would use to
// authenticate it) are marked as 'ephemeral' - meaning that the node will be disposed of as
// soon as it goes offline.
func start() -> TailscaleNode {
let dataDir = getDocumentDirectoryPath().absoluteString + "tailscale"
let authKey = "tsnet-auth-put-your-auth-key-key-here"
@@ -70,7 +74,7 @@ func start() -> TailscaleNode {
path: dataDir,
authKey: authKey,
controlURL: Configuration.defaultControlURL,
ephemeral: true)
ephemeral: false)
// The logger is configurable. The default will just print.
let node = try TailscaleNode(config: config, logger: DefaultLogger())
@@ -94,7 +98,18 @@ func fetchURL(_ url: URL, tailscale: TailscaleNode) async throws -> Data {
}
```
See the [TailscaleKitTests](./Tests/TailscaleKitTests/TailscaleKitTests.swift) for more examples.
The "node" created here should show up in the Tailscale admin panel as "TSNet-Test"
### LocalAPI
TailscaleKit.framework also includes a functional (though somewhat incomplete) implementation of
LocalAPI which can be used to track the state of the embedded tailscale instance in much greater
detail.
### Examples
See the TailscaleKitHello example for a relatively complete implementation demonstrating proxied
HTTP and usage of LocalAPI to track the tailnet state.
## Contributing

View File

@@ -27,6 +27,7 @@
C2BED05D2CCFC68D004A2544 /* libtstestcontrol.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2BED05C2CCFC68D004A2544 /* libtstestcontrol.a */; };
C2E1C30B2CC9EF1A00ADC565 /* libtailscale.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2E1C2FC2CC9B9E300ADC565 /* libtailscale.a */; };
C2E1C3142CCA8B7C00ADC565 /* TailscaleKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2E1C2DA2CC9B5A400ADC565 /* TailscaleKit.framework */; };
C2ED636A2DDE346900297161 /* libtailscale_ios_sim.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CE21942DD67A170096C105 /* libtailscale_ios_sim.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -59,10 +60,12 @@
C28640622CCA8C9D00CD5EBC /* TailscaleKitTestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TailscaleKitTestHost.app; sourceTree = BUILT_PRODUCTS_DIR; };
C28980E02DBFE3D40019B7EB /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
C2BED05C2CCFC68D004A2544 /* libtstestcontrol.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtstestcontrol.a; path = ../tstestconrol/libtstestcontrol.a; sourceTree = "<group>"; };
C2CE21942DD67A170096C105 /* libtailscale_ios_sim.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtailscale_ios_sim.a; path = ../libtailscale_ios_sim.a; sourceTree = "<group>"; };
C2E1C2DA2CC9B5A400ADC565 /* TailscaleKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TailscaleKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C2E1C2FC2CC9B9E300ADC565 /* libtailscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtailscale.a; path = ../libtailscale.a; sourceTree = "<group>"; };
C2E1C3102CCA8B7C00ADC565 /* TailscaleKitXCTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TailscaleKitXCTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
C2E3E87F2D2718D0004992A2 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
C2ED635B2DDE33B700297161 /* TailscaleKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TailscaleKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
@@ -93,6 +96,16 @@
);
target = C28640612CCA8C9D00CD5EBC /* TailscaleKitTestHost */;
};
C2ED635C2DDE33B700297161 /* Exceptions for "TailscaleKit" folder in "TailscaleKit iOS Sim" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
TailscaleKit.docc,
);
publicHeaders = (
TailscaleKit.h,
);
target = C2ED63522DDE33B700297161 /* TailscaleKit iOS Sim */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
@@ -119,6 +132,7 @@
exceptions = (
C2E1C2EC2CC9B5A400ADC565 /* Exceptions for "TailscaleKit" folder in "TailscaleKit macOS" target */,
C2525F4F2D7A22C100BD3CCA /* Exceptions for "TailscaleKit" folder in "TailscaleKit iOS" target */,
C2ED635C2DDE33B700297161 /* Exceptions for "TailscaleKit" folder in "TailscaleKit iOS Sim" target */,
);
path = TailscaleKit;
sourceTree = "<group>";
@@ -166,6 +180,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C2ED63552DDE33B700297161 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C2ED636A2DDE346900297161 /* libtailscale_ios_sim.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -189,6 +211,7 @@
C2E1C3102CCA8B7C00ADC565 /* TailscaleKitXCTests.xctest */,
C28640622CCA8C9D00CD5EBC /* TailscaleKitTestHost.app */,
C2525F4E2D7A22C100BD3CCA /* TailscaleKit.framework */,
C2ED635B2DDE33B700297161 /* TailscaleKit.framework */,
);
name = Products;
sourceTree = "<group>";
@@ -196,6 +219,7 @@
C2E1C2FB2CC9B9E300ADC565 /* Frameworks */ = {
isa = PBXGroup;
children = (
C2CE21942DD67A170096C105 /* libtailscale_ios_sim.a */,
C2525F532D7A258D00BD3CCA /* libtailscale_ios.a */,
C2BED05C2CCFC68D004A2544 /* libtstestcontrol.a */,
C2E1C2FC2CC9B9E300ADC565 /* libtailscale.a */,
@@ -220,6 +244,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C2ED63532DDE33B700297161 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
@@ -316,6 +347,29 @@
productReference = C2E1C3102CCA8B7C00ADC565 /* TailscaleKitXCTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
C2ED63522DDE33B700297161 /* TailscaleKit iOS Sim */ = {
isa = PBXNativeTarget;
buildConfigurationList = C2ED63582DDE33B700297161 /* Build configuration list for PBXNativeTarget "TailscaleKit iOS Sim" */;
buildPhases = (
C2ED63532DDE33B700297161 /* Headers */,
C2ED63542DDE33B700297161 /* Sources */,
C2ED63552DDE33B700297161 /* Frameworks */,
C2ED63572DDE33B700297161 /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
C2E1C2DC2CC9B5A400ADC565 /* TailscaleKit */,
);
name = "TailscaleKit iOS Sim";
packageProductDependencies = (
);
productName = Tailscale;
productReference = C2ED635B2DDE33B700297161 /* TailscaleKit.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -354,6 +408,7 @@
targets = (
C2E1C2D92CC9B5A400ADC565 /* TailscaleKit macOS */,
C2525F432D7A22C100BD3CCA /* TailscaleKit iOS */,
C2ED63522DDE33B700297161 /* TailscaleKit iOS Sim */,
C2E1C30F2CCA8B7C00ADC565 /* TailscaleKitXCTests */,
C28640612CCA8C9D00CD5EBC /* TailscaleKitTestHost */,
C2BED0552CCF3031004A2544 /* libtstestcontrol */,
@@ -390,6 +445,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C2ED63572DDE33B700297161 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -443,6 +505,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
C2ED63542DDE33B700297161 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -980,6 +1049,106 @@
};
name = Release;
};
C2ED63592DDE33B700297161 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/..";
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/..",
"$(SRCROOT)/TailscaleKit",
);
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 18.1;
LD_RUNPATH_SEARCH_PATHS = (
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SRCROOT)/..";
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
PRODUCT_BUNDLE_IDENTIFIER = io.tailscale.Tailscale;
PRODUCT_MODULE_NAME = TailscaleKit;
PRODUCT_NAME = TailscaleKit;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,7";
XROS_DEPLOYMENT_TARGET = 2.1;
};
name = Debug;
};
C2ED635A2DDE33B700297161 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/..";
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/..",
"$(SRCROOT)/TailscaleKit",
);
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 18.1;
LD_RUNPATH_SEARCH_PATHS = (
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(SRCROOT)/..";
MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
PRODUCT_BUNDLE_IDENTIFIER = io.tailscale.Tailscale;
PRODUCT_MODULE_NAME = TailscaleKit;
PRODUCT_NAME = TailscaleKit;
PROVISIONING_PROFILE_SPECIFIER = "";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,7";
XROS_DEPLOYMENT_TARGET = 2.1;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -1037,6 +1206,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
C2ED63582DDE33B700297161 /* Build configuration list for PBXNativeTarget "TailscaleKit iOS Sim" */ = {
isa = XCConfigurationList;
buildConfigurations = (
C2ED63592DDE33B700297161 /* Debug */,
C2ED635A2DDE33B700297161 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = C2E1C2D12CC9B5A400ADC565 /* Project object */;

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C2ED63522DDE33B700297161"
BuildableName = "TailscaleKit.framework"
BlueprintName = "TailscaleKit iOS Sim"
ReferencedContainer = "container:TailscaleKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "C2ED63522DDE33B700297161"
BuildableName = "TailscaleKit.framework"
BlueprintName = "TailscaleKit iOS Sim"
ReferencedContainer = "container:TailscaleKit.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -179,11 +179,11 @@ public actor TailscaleNode {
}
public struct LoopbackConfig: Sendable {
let address: String
let proxyCredential: String
let localAPIKey: String
public let address: String
public let proxyCredential: String
public let localAPIKey: String
var ip: String? {
public var ip: String? {
let parts = address.split(separator: ":")
let addr = parts.first
guard parts.count == 2, let addr else {
@@ -192,7 +192,7 @@ public actor TailscaleNode {
return String(addr)
}
var port: Int? {
public var port: Int? {
let parts = address.split(separator: ":")
let port = parts.last
guard parts.count == 2, let port else {

View File

@@ -0,0 +1,13 @@
#!/bin/sh
SDK=iphonesimulator
PLATFORM=ios-simulator
CLANGARCH=arm64
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`
exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -m${PLATFORM}-version-min=12.0 "$@"

View File

@@ -0,0 +1,13 @@
#!/bin/sh
SDK=iphonesimulator
PLATFORM=ios-simulator
CLANGARCH=x86_64
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`
exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -m${PLATFORM}-version-min=12.0 "$@"