In Objective-C we could add a C Flag of -DVAR_NAME=#\"string value\" and then get the value with NSString *var = VAR_NAME.
How do we do this in Swift?
An example of this would be defining an api host based on the current git branch. Say the branch is feature1 and it should connected to https://feature1.example.com. A shell script can easily find the current branch and add the C Flag. Then in Objective-C we can use the branch from the shell script to generate the api host url.
Update
I am not asking about boolean flags. I need to pass a string value.
Update 2
So far all I can come up with is to use a build script to generate a swift class.
Update 3
Another option is to add custom keys to the Info.plist. This isn't always an acceptable solution but for configuration values this works.
Macros are evil. They have been abused for things like this and it's not a clean solution. You have the following options (some of them already mentioned by you).
Info.plist
The most simple, easy to read and edit. Not good for big configurations.
Your own .plist.
Easy to read and edit (even from command line tools before the build, see PlistBuddy tool). Better for bigger configurations.
Auto generated code
Your code can contain an expression that can be matched easily, e.g.
let myConfigValue = "${MY-CONFIG-VALUE}".
You can replace those values easily using command line tools, e.g. sed. This basically replicates macros without using C preprocessor. This is not very clean but usable if you already have a build system that you don't want to change.
Multiple code variants
You can have a Swift file with configuration constants and use #if to switch between them.
Define a condition like this:
var window: UIWindow?
#if MYDEF
var textureRenderThread : TextureRenderThread?
#endif
In the Project->Build Settings->Swift Compiler->Custom Flags
Set "-D MYDEF" as the value for "Other Swift Flags"
Related
I have common files in several projects and I need to stop from compiling some lines and functions for project A, meanwhile it should be compiled for project B.
I know that I can use preprocessor. But it's not convenient for me. Is there any way to stop lines of code from compiling with condition like below?
#if PhotosModuleSettings.type == .documents
... do not commpile
#endif
What's not convenient about using the preprocessor? You can specify the preprocessor macros in build settings of each target, or you can use .xcconfig files to specify them.
There's another simple way to do it, however. Separate the lines and functions that you want to conditionally compile into separate files. Maybe by using Swift extensions or subclassing or just separate global functions, etc..whatever. Then just choose which target(s) and/or project(s) you want those files added as membership.
Depending on your desire to refactor your code to make such a file separation, the preprocessor macros may be the better way to go, though.
You will need to make use of pre processor macros.
Add a configuration for your project, and use that in the pre processor macros.
You can set the value for these configuration in the pre processor macros section for your targets based on your build configuration.
Here is a detailed blog related to the same concept
I need to write some license checking code in Swift. I know Swift is not optimal for that kind of code in the first place, as it is harder to obfuscate. But if the code that needs to know whether the app is registered is written in Swift, this is still better than putting the license checking code in a separate framework that can be swapped out.
To make attacking that code harder, I'm trying to obfuscate the code by at least removing the symbols related to it.
For this, I have some inlined methods with internal visibility as follows:
#inline(__always) static func checkLicense() { /* license checking code */ }
Given that the method should always be inlined, there should be no need to include the method's name in the binary's symbol table. (I know that inline annotations often only are hints to the compiler, but I have reason to believe that they do work in this case.)
In line with that, nm MyApp.app/Contents/MacOS/MyApp does not contain references to checkLicense.
However, the output of strings MyApp.app/Contents/MacOS/MyApp still contains references to checkLicense, and I'm afraid that an attacker could use that information to more easily attack the license checking code.
Here are my questions:
Will these strings help an attacker, or are they useless without the corresponding symbol info (which would be exposed by nm)?
Would the strip settings listed below (in particular, stripping all symbols) cause a problem when shipping my code - e.g. when trying to symbolicate stack traces? I do keep the dSYMs of the shipped binaries.
Would setting "Perform Single-Object Prelink" to Yes help in obfuscating the code? The only effect I can see is that the dSYMs size shrinks from ~8 MB to ~6 MB.
I am currently using the following build options:
Deployment Postprocessing = Yes
Strip Linked Product = Yes
Use Separate Strip = Yes
Strip Style = All Symbols
Other Linker Flags = "-Xlinker -x"
Perform Single-Object Prelink = No (see above)
I have investigated this again, and found the following strip settings to work well for Release builds:
Deployment Postprocessing = Yes
Strip Linked Product = Yes
Perform Single-Object Prelink = No
Use Separate Strip: Optional, doesn't make a difference
Strip Style:
All Symbols for the main app (equivalent to -Xlinker -s according to this guide)
Non-Global Symbols for libraries (equivalent to -Xlinker -x)
Other Linker Flags: None; already provided by "Strip Style"
In Objective-C I had a bunch of compiler flags set in Build Settings -> Other C Flags that were being used in the code. For instance:
Flag => -DPortNumber = 1
And in code I was able to access it by #(PortNumber)
This doesn't work in Swift, and I'm not able to find an answer.
The -D flag to C compilers defines a preprocessor macro. There are no preprocessor macros in Swift. So if you're looking to do something like:
// compile with -DPORT_NUMBER 31337
var port = PORT_NUMBER // error
... you can't. Swift is designed for source code to be syntactically complete before compilation. If you could switch out blocks of it at build time, you'd break the ability of the toolchain to help verify that your code is correct. (Partly this is because preprocessor macros in C are textual replacement: you can use them to rewrite any part of the language, not just fill in values for variables.)
The Swift compiler does have a -D flag, but its use is more limited: you can use it for build configurations only. So, if you wanted to do something like the following, you'd be cool:
// compile with -DUSE_STAGING_SERVER
#if USE_STAGING_SERVER
var port = 31337
#else
var port = 80
#endif
Note that unlike C, everything inside an #if block needs to be syntactically complete. (For example, you can't put just the declaration line of a func in an #if block and leave the function body outside the conditional.)
Of course, this doesn't help you if you want to have a configuration value set at compile time be used in your code. For that, I'd recommend alternate approaches. Xcode can still do textual substitution in resource files, like property lists. (Note that the Info.plist that comes with your app is full of things like $(TARGET_NAME), for example.) So, you could include a bundle resource with your app whose contents are populated at compile time according to your project settings, then read your port number from that.
is is possible to use macros in config files? I want to achieve something like:
if iPad
set variable to 1
else
set variable to 0
Is that possible? I would rather not use scripts for this.
You generally should check this at runtime rather than compile time. See iOS - conditional compilation (xcode).
If you don't do it that way, I typically recommend using different targets as hinted at by #Robert Vojta.
That said, I can imagine cases where this would be useful in some piece of shared code. So...
There is an xcconfig variable you can use called TARGETED_DEVICE_FAMILY. It returns 1 for iPhone and iPod Touch, and 2 for iPad. This can be used to create a kind of macro. I don't highly recommend this approach, but here's how you do it. Let's say you were trying to set some value called SETTINGS:
// Family 1 is iPhone/iPod Touch. Family 2 is iPad
SettingsForFamily1 = ...
SettingsForFamily2 = ...
SETTINGS = $(SettingsForFamily$(TARGETED_DEVICE_FAMILY))
I've done this a few times in my projects (for other problems, not for iPad detection). Every time I've done it, a little more thought has allowed me to remove it and do it a simpler way (usually finding another way to structure my project to remove the need). But this is a technique for creating conditionals in xcconfig.
AFAIK it's not possible. But if you want to solve simple task - lot of common settings and just few variables have different values, you can do this:
generic.xcconfig:
settings for both configs
ipad.xcconfig:
#include "generic.xcconfig"
ipad-specific-settings
iphone.xcconfig
#include "generic.xcconfig"
iphone-specific-settings
This can solve your condition need. I do use this schema frequently.
That's not possible. Configuration files are not preprocessed (and compiled). What are you trying to do?
This is a little convoluted, but lets try:
I'm integrating LUA scripting into my game engine, and I've done this in the past on win32 in an elegant way. On win32 all I did was to mark all of the functions I wanted to expose to LUA as export functions. Then, to integrate them into LUA, I'd parse the PE header of the executable, unmangle the names, parse the parameters and such, then register them with my LUA runtime. This allowed me to avoid manually registering every function individually just to expose them to LUA.
Now, flash forward to today where I'm working on the iPhone. I've looked through some Unix stuff and I've gotten very close to taking a similar approach, however I'm not sure it will actually work.
I'm not entirely familiar with Unix, but here is what I have so far on iPhone:
Step 1: Query for the executable path through objective-C and get the path of my app
Step 2: Use dlopen to get a handle to my app using: `dlopen(path, RTLD_NOW)`
Step 3: Use `dlsym( libraryHandle, objectName )` to attempt to get the address of a known symbol.
The above steps won't actually get me to where I want to be, but even that doesn't work. Does anyone have any experience doing this type of thing on Unix? Are there any headers or functions I can google to put me on the right track?
Thanks;)
iPhone does not support dynamic linking after the initital application launch. While what you want to do does not actually require linking in any new application TEXT, it would not shock me to find out that some of the dl* functions do not behave as expected.
You may be able to write some platform specific code, but I recommend using a technique developed by the various BSDs called linker sets. Bascially you annotate the functions you want to do something with (just like you currently mark them for export). Through some preprocessor magic they store the annotations, sometimes in an extra segment in the binary image, then have code that grabs that data and enumerates its. So you simply add all the functions you want into the linker set, then walk through the linker set and register all the functions in it with lua.
I know people have gotten this stuff up and running on Windows and Linux, I have used it on Mac OS X and various *BSDs. I am linking the FreeBSD linker_set implementation, but I have not personally seen the Windows implementation.
You need to pass --export-dynamic to the linker (via -Wl,--export-dynamic).
Note: This is for Linux, but could be a starting point for your search.
References:
http://sourceware.org/binutils/docs/ld/Options.html
If static linking is an option, integrate that into the linker script. Before linking, do "nm" on all object files, extract the global symbols, and generate a C file containing a (preferably sorted/hashed) mapping of all symbol names to symbol values:
struct symbol{ char* name; void * value } symbols = [
{"foo", foo},
{"bar", bar},
...
{0,0}};
If you want to be selective in what you expose, it might be easiest to implement a naming schema, e.g. prefixing all functions/methods with Lua_.
Alternatively, you can create a trivial macro,
#define ForLua(X) X
and then grep the sources for ForLua, to select the symbols that you want to incorporate.
You could just generate a mapfile and use that instead, no?