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.
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:
Remove -emit-dependencies
Remove -emit-module -emit-module-path FILEPATH
Remove -emit-objc-header -emit-objc-header-path FILEPATH
Remove -c (right before -jN and the list of files)
Remove -parseable-output
Add -dump-ast
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.
Related
I want to create a run command in notepad++, that cleans/deletes the compiled files whenever I press Ctrl + M. So far I created this line of code :
cmd /k c:\WinAVR-20100110\utils\bin\make.exe make clean $(FULL_CURRENT_PATH)
It does not work and gives this warning :
No Rule To make target clean
Which technically means the parameter is wrong, however I did not find a way to correct it.
Any Suggestions
You don't want to pass make as an argument to make because then it will look for a target named make which is not defined.
Also, you would need to make sure make is running in the right directory. One way to do that is use the -C option. For example:
make -C path/to/my/dir clean
Some unsolicited tips: WinAVR is really old, see how you are using the version from 2010-01-10? I'd recommend using MSYS2 for your Bash shell environment and then installing the latest AVR 8-bit toolchain from Atmel.
When using XCode to compile a Cocoa application, I'm running a custom Bash script in the build phase. Unfortunately, I'm having to spell out full paths. Instead, I'm almost certain there are variables I can use in the Bash and one of those might cover it. Here's what I'm running:
/Users/mike/Projects/objectivec/proj1/proj1/shellscript.sh /Users/mike/Projects/objectivec/proj1/proj1/proj1/lang/en/html/
See how having a $VAR would help here, rather than specifying physical paths? It would also help members on my team be able to compile this project without modification.
I tried looking in the XCode7 docs, but couldn't find any listing anywhere of what these variables might be that I can use.
Note that the path /Users/mike/Projects/objectivec/proj1/proj1/ folder contains my AppDelegate.mm file in this case, if that helps you.
Can you tell me where I can find the documentation on this list of available variables so that I don't have to specify full physical paths?
The fix was that I made it run this Bash script as a test:
#!/bin/bash
set > /tmp/vars.txt
Then, I compiled a build. After that, I looked in /tmp/vars.txt to see what was available to use. From there, I could use these directly both in my custom Bash script and in the black script field inside XCode, such as $SOURCE_ROOT.
I'm asking how to do this outside of Xcode.
A Swift script written in a text editor can be executed with xcrun swift hello_world.swift or swift hello_world.swift. They can also be set to executable and run with a shebang. This is parallel to a scripting language like Python.
But since Swift is a compiled language, I'm sure there has to be some way of building a Swift executable through the Terminal using swift, clang, etc. Has anyone found anything regarding this? I've surprisingly found nothing.
You need swiftc:
% cat > hello.swift << EOF
heredoc> println("Hello, world!")
heredoc> EOF
% swiftc hello.swift
% ./hello
Hello, world!
%
If you want to compile multiple files, the one you want to actually run on launch needs to be called main.swift (in which case you probably also want to use -o executablename).
Various options available via swiftc --help. The most likely one you want to use is -O to turn on the optimizer.
Also, depending on your environment settings, you may need to use xcrun -sdk macosx swiftc, if you are using Foundation or other SDKs.
I'm trying to figure out exactly how schemes work in xcode and what they're for. I have a cross-platform product that's built on OS X using an external build system ( scons ). I'd like to be able to build/debug it from Xcode, mostly because of the symbol search and the debugger. I've been using eclipse CDT which mostly works well, but has some quirks.
I can mostly get this to work by creating an empty project and adding an 'external build system' target. Then, as part of the 'Info' of the target, I specify the 'Build Tool' as /usr/local/bin/scons, and the 'Arguments' are the build parameters that I send to scons. Basically I have the following build variables called $(TARGET) and $(BUILD_TYPE) that vary according to whether the build is debug or release, so those can be specified as conditional 'Build Settings'.
The problem is I'd like Menu->Project->Clean to work. It looks like Xcode/xcodebuilder use the $(ACTION) variable to pass this on - where $(ACTTION) is either 'build', 'clean', or some other build actions. See xcodebuild ACTION. Scons is a bit different - it has a built-in clean action that's invoked on the command line with scons -c. So my first thought was to use a conditional 'Build Setting' to pass this parameter, but it turns out that conditional 'Build Settings' don't seem to vary based on the build ACTION - just the build architecture and SDK.
Is it possible to add an expression to a 'Build Setting' in Xcode/xcodebuilder? Is there another good way that I could get 'Clean' to work in Xcode with scons?
Write a wrapper script for SCons, and put it in your project. For example:
External Build Tool Configuration
Build Tool: $(PROJECT_DIR)/scons-xcode-wrapper.sh
Arguments: $(ACTION)
Wrapper Script
From an experiment, it looks like $(ACTION) is empty when building, and set to clean when cleaning.
#!/bin/sh
cd "$PROJECT_DIR"
case $1 in
clean)
scons -c
;;
*)
scons
;;
esac
Don't forget to chmod +x your script.
With SCons, you can programatically set the build to perform a clean using the SetOption() function. The clean option and others that can be set are listed here.
The problem is that SCons treats command line options that arent in the form "--option" or "option=value" as targets. So its not possible to cause something like scons clean to perform a clean. I tested with the Alias() function and could not get it to work.
If you have the option to change the string that xcode uses for $(ACTION) to something like clean=1 then you could something like the following to programatically do a clean:
env = Environment()
if ARGUMENTS.get('clean') == '1':
print "Setting clean"
env.SetOption('clean', True)
print env.GetOption('clean')
...
This will cause a clean:
scons clean=1
You could also consider the AddOption(), but this only allows for options with -- prepended
Set your 'Arguments' parameter to end with:
--$(ACTION)
This will translate to:
scons [all your arguments] --clean
If you check the docs for scons here, you can see that --clean works just as well as -c
Clean is the only one that works however, the other build actions always come through blank.
You can use a combination of the answers above, namely:
Set your arguments to something like --xcode-action=$(ACTION).
Put code in your SConstruct like this:
env.AddOption('--xcode-action',
dest='xcode_action',
type='string',
action='store',
default='',
help='The action Xcode wishes to perform')
if GetOption('xcode_action') == 'clean':
SetOption('clean', True)
This is basically the solution I'm using in scons-xcode.
I am trying to set up CMake to generate a MSVC (2010) solution for our project, and need to configure the projects so that they use our specific build system rather than compiling using the default command line.
Here's what the project file looks like for VS2008 (which we generate using another script that I'd like to get away from):
<Tool
Name="VCNMakeTool"
BuildCommandLine="../bam.bat -j %%NUMBER_OF_PROCESSORS%%"
ReBuildCommandLine="../bam.bat -j %%NUMBER_OF_PROCESSORS%% -c && ../bam.bat -j %%NUMBER_OF_PROCESSORS%%"
CleanCommandLine="../bam.bat -j %%NUMBER_OF_PROCESSORS%% -c "
Output="..\..\..\common\win32\container.exe"
PreprocessorDefinitions=""
IncludeSearchPath=""
ForcedIncludes=""
AssemblySearchPath=""
ForcedUsingAssemblies=""
CompileAsManaged=""
/>
It's basically the three CommandLine settings I'd like to be able to specify from my cmake config.
I've found the build_command command in the documentation but from the description it sounds like it does sort of the opposite of what I want, i.e. writes the command line it'll generate to a variable rather than take a string and set the command line to that.
Something that seems a bit related is the cross-compile feature in CMake but I'm sure if that is a good way to do this.
Basically I just want VS to run a batch file when I do a build and then parse the results back to get nice error messages etc.
It looks to me like what you want is simply a "custom command" in CMake parlance.
Something like:
set(custom_exe "${CMAKE_CURRENT_BINARY_DIR}/common/win32/container.exe")
add_custom_command(OUTPUT ${custom_exe}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bam.bat -j $ENV{NUMBER_OF_PROCESSORS}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bam.bat
)
add_custom_target(bam ALL DEPENDS ${custom_exe})
Maybe you need to write your own CMake Toolchain. You can see examples of toolchains in CMAKE_ROOT/share/Modules/Platform, or in CMake documentation, but i'm not sure whether cmake can generate MSVC solution for custom compiler.