Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to dump the AST while building an Xcode project?

Tags:

xcode

swift

I've been doing some work on analyzing Swift projects using their ASTs, and I would like to know if it is possible to generate it somehow when building a Swift project with Xcode.

Right now, I am able to print the AST on the terminal when running the swiftc -dump-ast command for single files and simple projects. However, it becomes harder when using it for more complex projects.

For this reason, I'd like to use xcode. I already tried to pass the -dump-ast flag to the compiler in Build Settings > Swift Compiler - Custom Flags > Other Swift Flags. The flag was indeed passed to the compiler (the output does report calling swiftc with the -dump-ast flag when building). I tried to build the project both with xcode and through the xcodebuildcommand below, but neither dumped the ast.

xcodebuild -target 'CompilingTest.xcodeproj' -scheme 'CompilingTest' -
configuration "Debug" -sdk iphoneos -arch "armv7" 
CONFIGURATION_BUILD_DIR="TestBuild" ONLY_ACTIVE_ARCH=NO

Now, I'm reasoning that either Xcode's build process redirects swiftc's output to some file, or it silences it somehow. Any thoughts?

Any help would be greatly appreciated.

like image 521
Marcel Rebouças Avatar asked Jun 15 '16 23:06

Marcel Rebouças


1 Answers

Dumping the AST of your app is not possible to do from only changing Xcode build settings. The main reason for this is that Xcode is making a lot of decisions about compiler flags to pass to swiftc which are not all compatible with dumping the AST and you cannot stop Xcode from doing this.

But it is possible to do outside of Xcode with Xcode's help (or in Xcode using my script mentioned below). To do this you'll need to capture the swiftc command Xcode runs for your project, and then change it a bit to dump the AST.

First, build your project, then go to the Report Navigator in Xcode (the last tab in the Navigator pane on the left). From here either save your entire build log with the save button across the top, or copy the swiftc command directly from Xcode. You're looking for the command called "Compile Swift Sources" for your app target (NOTE: this only contains the compile command for the one target, if you want the AST for multiple targets you'll need to perform these steps multiple times). If you can't find this step, you may need to clean your project and compile again (or look at an older build log).

After you've copied the entire swiftc command from Xcode, you'll need to head to the command line and change the command a bit. Here's what you'll need to do:

  1. Remove -emit-dependencies
  2. Remove -emit-module -emit-module-path FILEPATH
  3. Remove -emit-objc-header -emit-objc-header-path FILEPATH
  4. Remove -c (right before -jN and the list of files)
  5. Remove -parseable-output
  6. Add -dump-ast
  7. Append > output.ast 2>&1 to your shell command

Why these?

  • Numbers 1, 2, 3, and 4 must be removed because when dumping the AST you cannot also emit another type of file. You can see the logic around these errors in the open source Swift compiler here. Number 4 is a case of this since -c is an alias of -emit-object.
  • Number 5 makes it easier for you to redirect the AST output while also stopping swiftc from outputting other information about this command. If you plan to parse the output of this AST command from another program instead of redirecting the output in the shell you might want to leave this option in (you end up getting JSON with it).
  • Number 6 is what causes the command to output the AST. Depending on what you want to use this output for, you can also consider using -print-ast which prints a more class-dump style output vs the more verbose, classical parsable AST output of -dump-ast.
  • Number 7 is simple shell redirection so that you can redirect the (probably huge) output of your AST to a single file. Change output.ast to whatever file you want. You'll need 2>&1 because the AST is dumped to stderr instead of stdout. The order also matters here.

Also note that Xcode's build log escapes spaces but not other characters that shells may not like. For example if you have & in any of your folder / directory paths, you'll have to escape that manually.

If all of this sounds like too much work, I threw together a script to do this processing for you and you can set it up in Xcode. You can find it on GitHub.

like image 117
Keith Smiley Avatar answered Jan 08 '23 17:01

Keith Smiley