xcode 4: how can I add a custom compiler? - ios

Xcode seems to allow specifying a custom compiler for source files via the Build Rules tab (copy the system C rule to the target, select "Custom Script". Just for testing the concept, I wrote echo $* as the script.
However it doesn't really run that script (no output is sent to the console); the end result is that no file gets built, so later I get a link error.
Am I using it wrong? What's the correct way of using a custom compiler in Xcode 4.x?

I tried your example. The script would not run unless I added an output file to the Output Files table for the build rule. Then the script ran, but the results appear in the build transcript instead of the console. Open the log navigator by choosing View > Navigators > Show Log Navigator. Select your build from the log navigator to open the build results window. There should be a run custom shell script step in the build results window. On the right side of the step is a small button with several horizontal lines. Click that button to show the build transcript.
If you want to use a custom compiler on some of the files in your project, you may find it easier to add a Run Script build phase to your target and add the files you want to compile to the Run Script build phase.

Related

Xcode. How download files at the stage of project assembly?

I'm doing an iOS framework and now i need to implement something like this: At the stage of the project assembly, I want to make a request to the server, get the JSON in response and write it to the project file. Thus, the user who downloaded the application, and opened it without the Internet will already have these files. In Android, it is possible to implement this function using the Gradle plugin. What the right way to implement this in iOS? Thanks in advance for the answer.
You can use a Run Script phase in the Build Phases section of your project.
Step 1
Add the initial version of the file to your project. Make sure it's added to the target.
Step 2
Select your project and go the build phases tab. You should be able to see the file being copied to the bundle in the Copy Bundle Resources section.
Step 3
Add a new Run Script to your build. Click the plus button at the top-left of the editor.
Give the phase a sensible name by double clicking the label.
Reorder the phase as early as possible by dragging it up the list.
Step 4
Using your favourite scripting language/command line thing download the new file and replace the existing file.
e.g (untested demo bash sample, probably wont work)
MYFILE=${TEMP_DIR}/something.json
curl -o $MYFILE https://myserver.com/stuff/something-latest.json
cp -f $MYFILE ${SRCROOT}/Sploopy/Resources/something.json
You can examine the environment with the build inspector and see what values you can use to get the file in place.
Ones that will come in handy are:
TEMP_DIR is a good place to put files temporarily.
SRCROOT so you know where to copy the downloaded file to.
CONFIGURATION so you can choose when to do this action. Personally I would only do it on Release but YMMV. It will be a blocking action.
Step 5
Profit

Is it possible to script adding a directory of source files into an Xcode project for compile?

As part of our Unity build process we drag and drop a directory of C source files which are generated by the Unity IDE into our iOS Xcode project. We want Xcode to "Create groups" for the files because the header files don't seem to be recognized by the compiler when using "Create folder references".
I'm wondering if there's a way to script this so we don't have to manually drag the directories into Xcode each time. Adding a "Copy Files" build phase only seems to work if I choose "Create folder references". When I choose "Create groups", the "Copy Files" section remains empty. Is this a bug in Xcode or am I doing something wrong? I'm using Xcode 9.1.
I know Apple recommends creating a framework rather than copying in a directory of source files. The reason we can't do that is because we're relying on the Unity build process which gives us a bunch of C source files.
In Xcode, you can manage your build process under the "Build Phases" tab when you select your app target. These tasks are executed on each build of your app, unless specified otherwise by some phases (for example: you can choose to run a phase only when the app installs for the first time).
Click the + button and you can add a "Copy files phase" that will copy your selected files into the app. When adding the files you'll be able to select if added folders will create groups or folder references.
You can also add a custom "Run script phase" and write some bash code to do whatever you like, or even run an external script that will do more complex work.
Xcode makes it possible to script adding resource files such as images to the project file using the "Build Phases" tab however this does not work for source code files that need to be recognized at compile time. Luckily I managed to come across a nice community-developed Python script which does allow us to do this.
https://github.com/kronenthaler/mod-pbxproj
With this script we can make all sorts of modifications to the project file including adding or deleting files.
See this link for a full list of available operations:
https://github.com/kronenthaler/mod-pbxproj/wiki
xcode->Build Phases-> click (+) button -> New Copy Files Phase / New Run Script Phase

Apple Watch pre-build action to change storyboard customModule references

I currently have a project with 3 different versions of the same app (different branding and such), which is working just fine. I've since then added 3 new Apple Watch targets (1 for each app "version"), where which 2 of them reference the files in the "master" Apple Watch target.
Everything works fine as long as i remember to change the module reference for each storyboard view, so that it maps to the correct interface controller in the corresponding watchkit extension target.
However, remembering to switch this every time i need to run/build a app version/target is a pain and not really a long term solution.
I've created the following command which I want to be run at the correct time, such that it changes the storyboard references before it is compiled.
perl -pi.bak -e 's/customModule=\"(.*?)\">/customModule=\"watchMyTarget_Extension\">/g' ${SRCROOT}/watch/Base.lproj/Interface.storyboard
I also concluded that I would probably want to reset the change after the app was compiled, since I don't want to have a file change for git to complain about. Which is why the aforementioned script creates a .bak file. So after the compilation is done and packed/run on device or whatever, I want to run
mv ${SRCROOT}/watch/Base.lproj/Interface.storyboard.bak ${SRCROOT}/watch/Base.lproj/Interface.storyboard
I've tried placing the scripts in the target's (watchTarget, not appTarget) build scheme, Build->Pre/Post Actions which didn't seem to have any effect. And I tried putting it in Run->Pre/Post Actions which worked to some degree, but it seemed like the post action kicked in before the app was pushed to the simulator and thus crashing the application ("could not run see device logs" or something like that).
So where on earth do I need to put these scripts to have them run at the correct time in the build process?
you should use add New Run Script Phase in your target's Build Phases, place it before the Compile Sources
Steps: (from Apple)
In the project editor, select the target to which you want to add a
run script build phase.
Click Build Phases at the top of the project editor.
Choose Editor > Add Build Phase > Add Run Script Build Phase.
Disclose the Run Script section in the project editor.
Configure the script in the Run Script template.
My solution is to go the Build settings of each watch extension target, setting the Product module name to the same value, for example, xxx_watch_extension. Then we should be able to choose this module for custom classes on the storyboard.
It works fine for me.

When does an iOS program run `Run Script` and load Info.plist

Before I run my App, I would like to run a external shell to update my Info.plist.
With Build Phases->Run Script, I can run my external shell. And here is my question, I saw Info.plist update the data when the program was building, but when I ran into my app, I found that the data read from plist was the former old data.
I also found another funny thing.
One side, if I just built the project(command + B), I saw plist update and then I ran the program, the data showed in UI was new data.
Another side,if I used the Run Button in Xcode, I saw the Info.plist update when Xcode show build successed, however, the data showed in UI was old data.
So, what happens? Could you help me to solve it to let my data be always the newest.
=============
Now, I have moved my 'Run Script' to run external shell before 'Compile Source(swift files)', and it works. However, I still can't understand, since it runs during build time, why the running program can't get the right data from Info.plist if I runs my 'Run Script' after 'Compile Source(swift files)'? does the program load in the data during its run time or compile time?
Building an app involves many different phases. Compiling sources is just one of them, there's also linking, copying resources, signing, etc. Some of them are explicitly listed in the "Build Phases" tab, others are not.
So it's really a matter of running the script at the appropriate time in the build process so that the Info.plist is modified before it is actually used by the build process.
If you click on the "Report Navigator" icon (last icon in the list at the top of the left-side panel), then on the last build, you'll see the report of that build which lists all the steps that were performed during the build process, including running scripts and processing the Info.plist.

Running a Clang LibTooling tool over an iOS Xcode project

I've written a toy libtooling based tool that does some analysis/source rewriting over ObjectiveC code. How do I run it over an iOS Xcode project?
I've looked at compiling the application through commandline/clang, but I haven't got it to work yet. Is it possible to chain my tool with xcodebuild? Or is there a better way to run the tool over an Xcode project?
I think what you need is JSON-Compilation-Database.
You can use xctool to generate a json compilation databse (xctool has a reporter that generate this thing, see the readme.)
The json compilation database is just a json file which contains all the compiler options (say, the header search path, the frame work search path) that need to pass to the clang and libtooling based tools.
If you want your tool to generate errors and warnings in code it should be a clang plugin and you can just change your project clang flags to load the plugin.
In your case it seems like you are using libtooling that alters the source code, you can simply add your script to your project build process prior to the "Compile Sources" stage.
In Xcode -> Click on Project -> click on your desired Target -> Build Phases -> Click on Editor (Menu Bar) -> Add Build Phase -> Add Run Script
Drag the new Run Script to be before Compile Sources
Edit the run script phase to do what you want

Resources