Read URL string from .xcconfig file in code [duplicate] - ios

I have an xcconfig file which contains a configuration for which server my app should hit. In debug mode, this will be a different server than for release builds.
The problem I have is that a URL of the form http://www.stackoverflow.com is treated as a comment after the double slash. So the string I get in code is 'http:'
I have read that I can put a -traditional build flag on Info.plist, I was wondering if someone else has had a similar issue and has solved it?
Thanks.

Here's a simple workaround:
WEBSITE_URL = https:/$()/www.example.com

I also could not figure out how to use a double slash in a xcconfig file.
But I found a workaround in
Re: Double forward slashes in .xcconfig-defined build settings
from the Xcode-users mailing list: In the xcconfigfile, save the URL without the http scheme:
MYURL = stackoverflow.com
In the Info.plist, set the property value to
http://${MYURL}

Just declare
SIMPLE_SLASH=/
Then your URL becomes
http:$(SIMPLE_SLASH)/www.stackoverflow.com

SLASH=/
API_URL=http:$(SLASH)/endpoint.com

Another approach that improves readability could be:
PROTOCOL = http:/
API_URL = $(PROTOCOL)/www.stackoverflow.com
This way protocol can be used elsewhere

You shouldn't use a xcconfig file for this setting.
A xcconfig file is not a "normal" header or module file which is the input of the preprocessor and eventually the input for the compiler. It's nowhere specified how the xcconfig file parser treats character encoding, whether it recognizes escape sequences, whether it expands macros, and how character literals are defined and much more.
It's far better in this case, to have a "config.h" header file and use a conditional based on a preprocessor definition:
#if defined (DEBUG)
NSURL* url = ...
#else
NSURL* url = ...
#endif
Here, DEBUG is defined for Debug configuration by default. You may #define any other definition in the build settings under "Preprocessor Macros".

Related

IOS/Xcode: Suppress NSLog Statements for Release in 2018

Because NSLog statements slow down apps, it seems advisable to remove them prior to release. A number of older answers on SO going back to 2010 suggest putting some code in the pch file such as:
#ifndef DEBUG
#define NSLog(...);
#endif
However, Xcode no longer automatically creates a pch file. I gather it is possible to manually create a pch file but this seems like a bit of a kludge. Is manually creating a pch file and adding the above code to it still the recommended way to comment out NSLog statements prior to release or is there a more modern approach?
All the old answers I found (including adding a PCH file) didn't work for Swift. Here's what finally worked for me:
Define the DEBUG flag by adding "-D DEBUG" to "Other Swift Flags" in the build settings.
Add the following global code (I just put it in a file named Globals.swift):
#if !DEBUG
public func NSLog(_ format: String, _ args: CVarArg...) {
}
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
}
#endif
It is still possible to create a pre-compiled header, however this is discouraged, at least by default. To do this, edit the build settings for your target, and define a path to a Prefix Header.
Use a Logging Library
Perhaps you can use a logging library, like CocoaLumberJack, or here is a very simple one, that nonetheless works well.

Xcode Localizable.string multiple targets issue

I have a project with multiple targets, which represent the same app just with different styling and translations.
Since almost whole project looks the same for each target, I need to have just few strings in Localizable.strings file, that I need to be different. And I don't want to copy whole huge Localizable.strings file to each project just because of the fact it has few lines different.
It is required for me to have just 1 strings file because of third-party libraries/SDK that are included in project. So I cannot use tableName for localizedString.
The problem is - I need to have a flexible possibility to override just few lines from Localizable.strings for each target separately. And I don't like the idea just to copy whole file to each target, cause it will lead to annoying flow in the future, in case I will have 10 targets and I need to add 1 string to all of them.
The goal is to have 1 huge Localizable.strings file with all strings included, that would be common for all targets, and have small configuration for each target for the strings that should tell different. So target's file should kinda merge and override the one that is common.
AFAIK it is not natively supported by Xcode, so I'm probably looking for a script that would make it works.
So, script should look into common and target's Localizable files, merge them, and in case some keys are defined in both, then it should use the one from target's file.
Can anyone help me with such script?
P.S. Similar issue exists with .xcassets, and CocoaPods solves it by merging multiple assets into 1, and it works as expected - if some targets has an asset containing the image with the same name that is already included into a common asset, then the one from target will replace it.
P.S.2. Similar feature is natively supported for Android devs - each image, each translations can be overridden by "child" flawor, or whatever it is called :)
TL;DR:
Example project: https://github.com/JakubMazur/SO45279964
OK, the easier thing to do would be shell/python script, because it will work for every build server. I assume that you have a different scheme for each target (otherwise it will make no sense). So what you can do is:
Let's say your target is named:
target1
target2
target3
1) Create separate files contains all the strings that should be different (i will put it under Localizable directory.
Your Localizable.strings file may look like this:
"someGeneralString" = "General string 1";
"AppName" = "This is a string that you probably need to change";
"someOtherGeneralString" = "General string 2";
And any of your targetX.strings file may look like this:
"AppName" = "target[x]"
And here is how it should look like in your project:
Note that your target localizable files should has target membership set only to one target, but your Localizable.strings should be for all targets!
That's all for project configuration. Let's go to scripting (I will use python for that):
#!/usr/bin/python
import sys
supportedLanguages = ["en","pl"]
commonPath = ".lproj/Localizable.strings"
keys = ["AppName"]
class CopyLocalizable():
target = ""
def __init__(self,arg):
self.target = arg
self.perform()
def perform(self):
for lang in supportedLanguages:
pathToLocalizable = lang+commonPath
textToFile = ""
with open(pathToLocalizable,"r") as languageFile:
for line in languageFile.readlines():
for key in keys:
if key in line:
textToFile += self.foundAndReplace(key,lang)
else:
textToFile += line
self.saveInFile(pathToLocalizable,textToFile)
def foundAndReplace(self,key,lang):
pathToTargetFile = "Localizable/"+lang+".lproj/"+self.target+".strings"
with open(pathToTargetFile,"r") as targetFile:
for targetLine in targetFile.readlines():
if key in targetLine:
return targetLine
def saveInFile(self,file,stringToSave):
with open(file,"w+") as languageFile:
languageFile.write(stringToSave)
You can optimize it yourself. It's easier script i can think about to get a job done.
And in the end let's automate it a bit:
- Go to your target
- add a new build phase
- Add a new script:
export PATH="/usr/local/bin:$PATH"
cd SO45279964/
python localize.py target[x]
and watch a magic happen ;)
http://www.giphy.com/gifs/26n6NKgiwYvuQk7WU
Here you can find example project that I've created to run this example:
https://github.com/JakubMazur/SO45279964
To keep it simple, Have a Macro defined for each target in Build Settings & define target specific strings within macro section like
#ifdef __TARGET__
//key values in localizable file
#endif

Xcode 7.3: "Ambiguous expansion of macro" when re-defining macro in prefix file

I am using Xcode 7.3, and I am getting an "Ambiguous expansion of macro" warning, for a macro which was defined in Foundation, but which I have undefined and re-defined in my prefix file. I have modules enabled.
To reproduce:
Set "Enable Modules (C and Objective-C)" to Yes in build settings
Use the following prefix file:
#import <Foundation/Foundation.h>
#undef assert
#define assert(e) NSLog(#"hi") // implementation is not important
Use the following main source file:
int main() {
assert(42);
return 0;
}
Then build in Xcode.
It shows an "Ambiguous expansion of macro 'assert'" warning on the line in the source file that uses the "assert" macro. The "Expanding this definition of 'assert'" points to the definition from the system header, not my redefinition. The "Other definition of 'assert'" points to the definition in my prefix file.
This warning does not happen when modules is disabled.
This is a bug in Xcode; we'd appreciate if you could file a bug report at https://bugreport.apple.com and leave the bug # in a comment here. Your options for working around this bug in the meantime are:
You could use a different name than "assert" for this macro.
You could set the GCC_PRECOMPILE_PREFIX_HEADER build setting to NO, since PCH don’t provide a lot of benefit when you already have modules. The prefix header will still work, it just won’t be turned into a PCH.
You could turn off modules.

How do I configure full URLs in xcconfig files

I have an xcconfig file which contains a configuration for which server my app should hit. In debug mode, this will be a different server than for release builds.
The problem I have is that a URL of the form http://www.stackoverflow.com is treated as a comment after the double slash. So the string I get in code is 'http:'
I have read that I can put a -traditional build flag on Info.plist, I was wondering if someone else has had a similar issue and has solved it?
Thanks.
Here's a simple workaround:
WEBSITE_URL = https:/$()/www.example.com
I also could not figure out how to use a double slash in a xcconfig file.
But I found a workaround in
Re: Double forward slashes in .xcconfig-defined build settings
from the Xcode-users mailing list: In the xcconfigfile, save the URL without the http scheme:
MYURL = stackoverflow.com
In the Info.plist, set the property value to
http://${MYURL}
Just declare
SIMPLE_SLASH=/
Then your URL becomes
http:$(SIMPLE_SLASH)/www.stackoverflow.com
SLASH=/
API_URL=http:$(SLASH)/endpoint.com
Another approach that improves readability could be:
PROTOCOL = http:/
API_URL = $(PROTOCOL)/www.stackoverflow.com
This way protocol can be used elsewhere
You shouldn't use a xcconfig file for this setting.
A xcconfig file is not a "normal" header or module file which is the input of the preprocessor and eventually the input for the compiler. It's nowhere specified how the xcconfig file parser treats character encoding, whether it recognizes escape sequences, whether it expands macros, and how character literals are defined and much more.
It's far better in this case, to have a "config.h" header file and use a conditional based on a preprocessor definition:
#if defined (DEBUG)
NSURL* url = ...
#else
NSURL* url = ...
#endif
Here, DEBUG is defined for Debug configuration by default. You may #define any other definition in the build settings under "Preprocessor Macros".

How do I make sure that a directory name is quoted in OMake?

I have a relatively complicated suite of OMake files designed for cross-compiling on a specific platform. My source is in C++.
I'm building from Windows and I need to pass to the compiler include directories which have spaces in their names. The way that the includes string which is inserted in the command line to compile files is created is by the line:
public.PREFIXED_INCLUDES = $`(addprefix $(INCLUDES_OPT), $(set $(absname $(INCLUDES))))
At some other point in the OMake files I have a line like:
INCLUDES += $(dir "$(LIBRARY_LOCATION)/Path with spaces/include")
In the middle of the command line this expands to:
-IC:\Library location with spaces\Path with spaces\include
I want it to expand to:
-I"C:\Library location with spaces\Path with spaces\include"
I don't want to change anything but the "INCLUDES += ..." line if possible, although modifying something else in that file is also fine. I don't want to have to do something like change the definition of PREFIXED_INCLUDES, as that's in a suite of OMake files which are part of an SDK which may change beneath me. Is this possible? If so, how can I do it? If not, in what ways can I make sure that includes with spaces in them are quoted by modifying little makefile code (hopefully one line)?
The standard library function quote adds escaped quotes around its argument, so it should do the job:
INCLUDES += $(quote $(dir "$(LIBRARY_LOCATION)/Path with spaces/include"))
If needed, see quote in Omake manual.
In case someone else is having the same problem, I thought I'd share the solution I eventually went with, having never figured out how to surround with quotes. Instead of putting quotes around a name with spaces in it I ended up converting the path to the short (8.3) version. I did this via a a simple JScript file called shorten.js and a one line OMake function.
The script:
// Get Access to the file system.
var FileSystemObject = WScript.CreateObject("Scripting.FileSystemObject");
// Get the short path.
var shortPath = FileSystemObject.GetFolder(WScript.Arguments(0)).ShortPath;
// Output short path.
WScript.StdOut.Write(shortPath);
The function:
ShortDirectoryPath(longPath) =
return $(dir $(shell cscript /Nologo $(dir ./tools/shorten.js) "$(absname $(longPath))"))
So now I just use a line like the following for includes:
INCLUDES += $(ShortDirectoryPath $(dir "$(LIBRARY_LOCATION)/Path with spaces/include"))

Resources