Skip to content

Instantly share code, notes, and snippets.

@roop
Last active January 2, 2021 12:30
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save roop/ec05db594fae8fd2a8eb to your computer and use it in GitHub Desktop.
Save roop/ec05db594fae8fd2a8eb to your computer and use it in GitHub Desktop.
Script to create a Makefile to build your Swift project
#!/usr/bin/perl -w
use strict;
# Makefile generator for quick compilation of Swift projects
# By: Roopesh Chander
# Thanks: Andy Matuschak
# Works only for swift-only projects.
# Usage:
# > perl makemake.pl
# > make
# More info: http://roopc.net/posts/2014/speeding-up-swift-builds/
my $APP_NAME = 'AppName'; # FIXME: Set project name here
my @SOURCES = (
'Path/To/File1.swift',
'Another/File2.swift',
# FIXME: Add swift files in your project here
# Escape spaces, if any:
'Somewhere\ else/Filename\ With\ Spaces.swift'
);
my $XCODE_DEV = "/Applications/Xcode.app/Contents/Developer";
my $SDK = "${XCODE_DEV}/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.1.sdk";
my $XCTOOL_PATH = "${XCODE_DEV}/Toolchains/XcodeDefault.xctoolchain";
my $SWIFT = "${XCTOOL_PATH}/usr/bin/swift";
my $XCODE_DERIVED_DATA = "$ENV{HOME}/Library/Developer/Xcode/DerivedData";
my $OBJ = "${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/Objects-normal/x86_64/";
my $TARGET = "${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator/${APP_NAME}.app/${APP_NAME}";
my $common_compile = "-target x86_64-apple-ios8.0 -target-cpu core2 -sdk $SDK -I ${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator -F ${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator -g -module-cache-path ${XCODE_DERIVED_DATA}/ModuleCache -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/swift-overrides.hmap -Xcc -iquote -Xcc ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-generated-files.hmap -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-own-target-headers.hmap -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-all-target-headers.hmap -Xcc -iquote -Xcc ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-project-headers.hmap -Xcc -I${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator/include -Xcc -I${XCODE_DEV}/Toolchains/XcodeDefault.xctoolchain/usr/include -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/DerivedSources/x86_64 -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/DerivedSources -Xcc -DDEBUG=1";
open (my $fh, ">", "Makefile")
or die "Cannot open Makefile for writing - $!\n";
print $fh <<END;
# Makefile for quick compilation of Swift projects
# Generated by $0
quick_compile: $TARGET
END
my @stubs = ();
foreach my $s (@SOURCES) {
my @p = split(/\//, $s);
my $f = $p[-1];
$f =~ s/\.swift$//;
my $other_sources = join(" ", grep { $_ ne $s } @SOURCES);
print $fh <<END;
$OBJ/${f}.o: $s
\t$SWIFT -frontend -c -primary-file $s $other_sources $common_compile -emit-module-doc-path $OBJ/${f}~partial.swiftdoc -Onone -module-name ${APP_NAME} -emit-module-path $OBJ/${f}~partial.swiftmodule -serialize-diagnostics-path $OBJ/${f}.dia -emit-dependencies-path $OBJ/${f}.d -o $OBJ/${f}.o
END
push @stubs, $f;
}
my $objs_str = join(" ", map { "$OBJ/${_}.o" } @stubs);
my $partmods_str = join(" ", map { "$OBJ/${_}~partial.swiftmodule" } @stubs);
my $common_merge = "-parse-as-library -target x86_64-apple-ios8.0 -target-cpu core2 -sdk $SDK -I ${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator -F ${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator -g -module-cache-path ${XCODE_DERIVED_DATA}/ModuleCache -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/swift-overrides.hmap -Xcc -iquote -Xcc ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-generated-files.hmap -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-own-target-headers.hmap -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-all-target-headers.hmap -Xcc -iquote -Xcc ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}-project-headers.hmap -Xcc -I${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator/include -Xcc -I${XCODE_DEV}/Toolchains/XcodeDefault.xctoolchain/usr/include -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/DerivedSources/x86_64 -Xcc -I${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/DerivedSources -Xcc -DDEBUG=1 -emit-module-doc-path ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/Objects-normal/x86_64/${APP_NAME}.swiftdoc -module-name ${APP_NAME} -emit-objc-header-path ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/Objects-normal/x86_64/${APP_NAME}-Swift.h";
print $fh <<END;
$OBJ/${APP_NAME}.swiftmodule: $objs_str
\t$SWIFT -frontend -emit-module $partmods_str $common_merge -o $OBJ/${APP_NAME}.swiftmodule
END
print $fh <<END;
$TARGET: $OBJ/${APP_NAME}.swiftmodule
\texport IPHONEOS_DEPLOYMENT_TARGET=8.0 && export PATH="${XCODE_DEV}/Platforms/iPhoneSimulator.platform/Developer/usr/bin:${XCODE_DEV}/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin" && ${XCTOOL_PATH}/usr/bin/clang -arch x86_64 -isysroot $SDK -L${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator -F${XCODE_DERIVED_DATA}/Build/Products/Debug-iphonesimulator -filelist ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/Objects-normal/x86_64/${APP_NAME}.LinkFileList -Xlinker -rpath -Xlinker \@executable_path/Frameworks -Xlinker -objc_abi_version -Xlinker 2 -L${XCODE_DEV}/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -Xlinker -add_ast_path -Xlinker ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/Objects-normal/x86_64/${APP_NAME}.swiftmodule -mios-simulator-version-min=8.0 -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __entitlements -Xlinker ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/${APP_NAME}.app.xcent -Xlinker -dependency_info -Xlinker ${XCODE_DERIVED_DATA}/Build/Intermediates/${APP_NAME}.build/Debug-iphonesimulator/${APP_NAME}.build/Objects-normal/x86_64/${APP_NAME}_dependency_info.dat -o $TARGET
END
close $fh;
@NachoSoto
Copy link

This is awesome, thank you so much!
The only issue I've found is that it assumes no spaces in filenames or paths. I tried adding quotes in each necessary place but my lack of Perl foo failed me :(

@roop
Copy link
Author

roop commented Dec 18, 2014

Thanks. Glad this is of help.

To handle spaces in the path or filename (which I hadn't thought of before), you can escape the spaces with a backslash, so the command line recognises that it's a single path. I've updated the script to illustrate this scenario.

@thewodros
Copy link

Very nice, thanks for sharing!

I was wondering if this can be tweaked for a Swift/Objective-C mix project. Any pointer? :) Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment