Xcode 12 performs a binary signing after all steps of the build have ended, including any custom post-build steps.
However I need to run a script to be performed after signing (e.g. for copying the signed binary elsewhere - but also for other things).
After having read a few StackOverflow questions and replies, I tried the following (separately):
Create an aggregate target with two subtargets that (1) performs the build & sign, (2) runs the final post build.
Use the scheme's build post-action to run the final post build.
Both don't work out of the box, and the problems are:
Aggregate target solution (if it worked): means that I have to create and maintain such a target for all of my many projects.
Post-action: does not appear in the build transcript, which makes it very cumbersome to detect errors. Moreover, a failure in the post-action does not fail the build - which is an absolute no-no.
In both cases the custom user definitions are not passed into any of the steps, which renders my script useless, as it relies heavily on those definitions.
Is there any proper solution to the seemingly trivial request for a post-sign action?
The workaround I found was this: As a post-build step, copy the binary elsewhere, perform any required operations on it, and then manually sign it.
Xcode will sign the original binary which is of no use to me.
Related
I can't count how many times I've opened a Xcode project instead of a workspace and spent a half hour trying to figure out what I've done wrong because none of the dependancies can be found.
Is there a way to detect this and generate a helpful error message in my compiler prefix?
I could try importing one of the headers that isn't always available, but I'd prefer something more direct and obvious if possible. (Mostly because if I rely on a particular header, that only really checks one package. It also imports the header so I don't need to #import it from my other code.)
You might use a pre-action Build phase script in your scheme to check the build path and take some action if it's wrong. In your workspace, you can specify a custom build path for workspace-wide stuff. If the path doesn't match, you know your target is being built from project only. (It's unfortunate that Apple doesn't provide an environment variable for the workspace and that even workspace-level schemes give the target's project as the project path.) But this is fiddly and seems gross. You ought to feel dirty even considering it, and guilty at having caused me to write it. What would your mother think?
Another (better, IMO) approach is to Manage Schemes when opened as Workspace and change the Container for all schemes to your workspace vs. project-level. This ensures there are no schemes available to build if the project itself is opened. You'll see "No Scheme" and any attempt to build, run, whatever, will give you an error beep.
I have five RT targets that run almost equal code. I don't want to copy the VIs around to every target. Obviously because I don't want to recopy everything when changes happen. My prefered way would be that I write one VI with some conditional disable or case structures where the desicion whether it's enabled or not should be made with a build file/script.
To achive the case switching I'd like to define string constants in a build script and the dead code elemination should remove the unused cases after compilation.
What are the right tools to achive that? And how would you combine that with CI?
There's no API today to do this from the build, but I would suggest that a conditional disable structure is what you want. There are some ideas on the LV idea exchange requesting this functionality.
Some options:
I believe you can set the condition value per-target, so you can have one target for each build and set a different value for each target. Or you could have multiple projects and have a different value for each project.
The CDS should have a target condition. I'm not sure how detailed you can make that condition, because I rarely work with targets.
While there's no proper API, you can call a pre-build VI and set the condition's value in the project/target programmatically using a tag. Haven't done this myself, but there are examples here and here.
I'm not sure how this would work with CI, as I don't do automated builds. I'm guessing once it's part of the build spec, it will simply be executed when you call the build spec.
I have a project whose make process generates different build artifacts for each configuration, e.g. if initiated with make a=a0 b=b0 it would build object files into builds/a0.b0, generate a binary myproject.a0.b0, and finally update an ambiguous executable link to point to the most recently built project ln -s myproject.a0.b0 myproject. For this project, this is a useful feature mainly because:
It separates the object files for different configurations (so when I rebuild in another configuration I don't have to recompile every single source with new defines and configurations set, (unfortunately) a very common procedure).
It retains the binaries for each configuration (so it's not required to rebuild to use a different configuration if it has already been built).
It makes a copy (or link) to the last built binary which is useful in testing.
Right now this is implemented in an ugly decades-old non-portable Makefile. I'd like to reproduce the same behavior in CMake to allow easier building on other platforms but I have not been able to reproduce it in any reasonable manner. It seems like adding targets with add_library/executable, but doing this for each possible permutation of input parameters seems wrong. And I'm not sure I could get the utilization correct, allowing make, make a=a0, make b=b0 a=a0 as opposed to what specifying a cmake target would require: make myproject-a0.b0.
Is this possible to do in cmake? Namely:
Specify the build directory based on input parameters.
Accept the parameters as make arguments which can be left out (defaulted) to select the appropriate target at the level of the makefile (so it's not required to rerun cmake for a new configuration).
I just can't figure out how to do this.
I have a special Build Configuration alongside Debug and Release. (Let's call it Foo)
My CFBUndleIdentifier is com.my-company.our-project.
However, when I build (and archive) for the Foo configuration, I want to use the bundle identifier com.my-company.foo.our-project
Is this possible? Everything I've tried has failed.
I spend much of my day building a white-label product, so I have to do this all the time.
The solution we came up with was to use an Xcode "Run Script" build phase as a "postflight" script.
In your project file, select the target, Build Phases, and then add a new "Run Script" build phase. I renamed the phase to "postflight" and ensured to move the phase to be the last thing done amongst all the build phases.
The essential thing the postflight script does is look for the built .app package, look for the Info.plist within it, and then change the CFBundleIdentifier within it for whatever our present build configuration is set for. Our script does a lot more than just this (other logic, post-processing, resource manipulations, etc.).
I can't provide too many specifics since my setup is customized for me, and yours is obviously customized for you. But that's the basic approach. Hopefully it'll work for you.
Hey, I'm implementing MD5 checksum on my app(for preventing binary crack). I created a command line tool that will generate the hash for the binary and will add it to the .app folder. However, I didn't figure out how to add it as a build phase. I've read Apple's documentation with no luck. Could anyone explain me how to do that step by step?
Thanks!
To do any kind of post-processing, use a Run Script build phase (add such a phase to your target). Use the list of environment variables Xcode provides (you can see them when the phase runs by expanding the script's results in the build results window) to locate the binary. From there you know where its Resources file is. The rest is standard Unix command-line stuff (run the command line and put the file into the target folder).
Now for advice you didn't ask for: It's trivial to re-hash the modified binary and replace yours with the new one in the resources folder. Anyone experienced enough to crack binaries would likely just disable the call to your "verify the MD5 against a file" code anyway, eliminating the need to replace the saved hash altogether. Long story short: You're wasting your time with this approach. :-)