Skip to content

Latest commit

 

History

History

build_ios_app

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Build iOS App without Xcode

This topic demonstrates how to build and debug an iOS app without an IDE or a build system.

cd llios/build_ios_app
./build.sh [--device] [--release]   # build the iOS app
./launch.sh  # launch the app in the simulator or device
./debug.sh   # launch the app and attach lldb to it

The demonstration includes

  • building static libraries
  • building Swift and Objective-C dynamic libraries
  • building an executable
  • packaging an app bundle
  • code signing
  • attaching lldb to the app
  • launching an app in a simulator or a device

Screenshots

Simulator Device
Simulator Simulator

Toolchain

swiftc

-c (-emit-object)

Generate a object file.

-emit-library

Directly Generate a dynamic library.

-wmo (-whole-module-optimization)

Here is the Apple's words for WMO. WMO can take multiple source files and generate one object. Because of this, -wmo doesn't work with some other flags. For example, with --index-store-path it will yield error "index output filenames do not match input source files".

swiftc -wmo -o one.o source1.swift source2.swift

-incremental

-incremental is the opposite to -wmo. It generates each a .o file for every .swift source file. -incremental requires an output file map provided by -output-file-map.

{
  "": {
    "swift-dependencies": "Build/StatiLib-master.swiftdeps"
  },
  "Sources/StaticLib/foo.swift": {
    "dependencies": "Build/foo.d",
    "diagnostics": "Build/foo.dia",
    "llvm-bc": "Build/foo.bc",
    "object": "Build/foo.o",
    "swift-dependencies": "Build/foo.swiftdeps",
    "swiftmodule": "Build/foo~partial.swiftmodule"
  },
  "Sources/StaticLib/bar.swift": {
    ...
  }
}

The swift driver with -incremental calls swift frontend with -primary-file for each source file and at the end it merges the module. (-primary-file is a frontend flag, which cannot be passed directly swift driver.)

> swiftc -incremental -output-file-map output_file_map.json Sources/StaticLib/bar.swift Sources/StaticLib/foo.swift -###

swiftc -frontend -c -primary-file Sources/StaticLib/bar.swift Sources/StaticLib/foo.swift -emit-module-path Build/bar.swiftmodule -parse-as-library -module-name StaticLib -o Build/bar.o
swiftc -frontend -c Sources/StaticLib/bar.swift -primary-file Sources/StaticLib/foo.swift -emit-module-path Build/foo.swiftmodule -parse-as-library -module-name StaticLib -o Build/foo.o
swiftc -frontend -merge-modules -emit-module Build/bar.swiftmodule Build/foo.swiftmodule -parse-as-library -module-name StaticLib -o Build/StaticLib.swiftmodule

-parse-as-library

Parse the input file(s) as libraries, not scripts. Without this, swiftc generates the main method for each compilation unit.

ld

-install_name

Install name, which is unique on Darwin platform, provides a dylib search path. It's set by passing -install_name to the linker (ld) when building a dylib (not an executable). In other words, install name is an attribute of a dylib itself. When -install_name path/to/DynamicLib.dylib is given, it ends up to a load command (LC_ID_DYLIB) in the dylib's macho-o load section.

Load command 3
          cmd LC_ID_DYLIB
      cmdsize 56
         name path/to/DynamicLib.dylib (offset 24)
   time stamp 1 Wed Dec 31 16:00:01 1969
      current version 0.0.0
compatibility version 0.0.0

When linking againt a dylib, a different load command (LC_LOAD_DYLIB) was added to the executable.

Load command 12
          cmd LC_LOAD_DYLIB
      cmdsize 56
         name path/to/DynamicLib.dylib (offset 24)
   time stamp 2 Wed Dec 31 16:00:02 1969
      current version 0.0.0
compatibility version 0.0.0

The install name can start with @executable_path, @loader_path, or @rpath, to provide a relative search path.

Note: -install_name is a linker flag. If calling from swift driver, we need to use -Xlinker.

Learn more

libtool

Unlike -emit-library, I didn't find a flag for building a static library, so we need to use libtool -static to create a static library.

codesign

# Sign an apple bundle
codesign --force --sign {identity} Build/SampleApp.app
# Show signing info
codesign -vvvvv -d Build/SampleApp.app
# Verify signing
codesign -v --verify Build/SampleApp.app

simctl

xcrun simctl shutdown all
xcrun simctl boot "iPhone 12"
xcrun simctl install booted "Build/SampleApp.app"
xcrun simctl launch booted "me.qyang.SampleApp"