Building an OS X command-line utility in release mode

I've written a simple command-line utility in Swift to help me parse and process some data files. The project only has about 400 lines of code, and uses some basic string handling, arrays, and dictionaries. I expect the resulting executable to be fairly small.


I use:

- Swift 3

- Xcode 8 beta 2 (8S162m)

- OS X 10.11.5.


The executable I build through Xcode ends up being 7.3M - much larger than I would expect.


However, when I compile the same code from the command line, using swiftc, the resulting file is about 120K - closer to what I would expect.


Some additional details:

- I'm building the Xcode project using using Product > Build For > Running.

- The executable is generated in the Build/Products/Release subdirectory of my project.

- Both Xcode and command-line compilation is done with -O -whole-module-optimization.

- Commenting out all my code in the Xcode project still results in a 5M executable.


What is the proper procedure for building a release version of a comand line utility using Xcode? I'm I doing something silly - like building the executable in debug mode without realizing it - or is this a bug due to the beta state of the toolchain?




Take a look at the General tab of your project item, and see if it's linking against system frameworks. It may be linking against Foundation (or somthing that implies Foundation), in which case I think you might get some of the Foundation APIs reimplemented for Swift (e.g. NSString), which are for now linked "into", rather than linked "against".


Compiling from the command line doesn't reference Foundation unless you explicitly imported it.


(This "fix" is speculation, but I wouldn't be surprised if something like this is the problem. The other thing you can do is use command line tools to examine the global symbols in your larger executable, and see if you can figure out what's got included that you don't need.)

Thank you for the tip. I have to import Foundation to access some of the String functionality that seems to be implemented in NSString. If I specifically import Foundation.NSString, the file does not change.


Using nm shows 188 global symbols (432 total) in the executable compiled with swiftc, and a whopping 19000 global (29000 total) symbols in the one compiled with Xcode - over 3000 related to Foundation alone.


So it looks like Xcode links a large number of unnecessary APIs into my executable. I can't figure out why, though - there is nothing listed in General > Linked Frameworks and Libraries or Build Phases > Link Binary with Libraries. Is there anywhere else I should look?


I might have to re-write my code in Swift 2 and compile is using Xcode 7.3, just to see if it makes a difference.

If you can demonstrate the difference straightforwardly, then you should definitely submit a bug against (probably) Xcode. Presumably there's nothing sinister going on, just a default setting causing linking against more libraries than necessary.


Also, if you want immediate relief, I strongly recomment you go post over in the swift.org forums. There may be a simple workaround that's already known or could be easily discovered.

Building an OS X command-line utility in release mode
 
 
Q