I have code with various parts which can be enabled or disabled with macros.
This can be done with #ifdef/#endif in the code, with -D options in the makefile and by calling make with setting the macro. Example:
make DOMP=-DUSE_OMP
In the makefile
calco.o: calco.cpp calco.h
$(CC) calco.cpp -o calco.o $(DOMP)
in the code
#ifdef USE_OMP
#pragma omp parallel for
#endif
for (i =0; i < N; i++) {
...
}
I have quite a few of possible macros that can be set and would like to be able to have these set simply by making a different target. For example
make calc_abc
would build my application using a particular set of macros, whereas
make calc_xyz
would do this with a different set of macros.
I tried different approaches in my makefile, but found nothing that worked.
Is something like this possible at all?
You can use target-specific variables for this. One of the features of target-specific variables is that they're inherited by their prerequisites. So:
calc_abc : CPPFLAGS += -DUSE_ABC
calc_xyz : CPPFLAGS += -DUSE_XYZ
calc_abc : calc
calc_xyz : calc
calc: foo.o bar.o
Of course, the trick here is you must be SURE to run make clean in between these different types of builds, because otherwise you'll get a mishmash of objects built different ways. If you think you'll commonly want to have things built different ways and co-existing, then typically you'd choose to put the object files in different subdirectories based on the type. Then they won't interfere with each other.
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
While using ReasonML and Bucklescript, is it possible to configure Bucklescript so it won't generate export statements? I'd prefer if the generated code could be used as is in a browser, that is, being ES5 (or ES6) compatible.
Edit: OK, while trying out the tool chain a bit more, I realize just turning off the export is not enough. See example below:
function foo(x, y) {
return x + y | 0;
}
var Test = /* module */[
/* foo */foo
];
exports.Test = Test;
This code will pollute global namespace if exports is removed, and is simply broken from an ES5 compatibility viewpoint.
Edit 2: Reading on Bucklescript's blog, this seems not possible:
one OCaml module compiled into one JavaScript module (AMDJS, CommonJS, or Google module) without name mangling.
Source.
BuckleScript can output modules in a number of different module formats, which can then be bundled up along with their dependencies using a bundler such as webpack or rollup. The output is not really intended to be used as a stand-alone unit, since you'd be rather limited in what you could do in any case, as the standard and runtime libraries are separate modules. And even something as trivial as multiplication will involve the runtime library.
You can configure BuckleScript to output es6 modules, which can be run directly in the browser as long as your browser supports it. But that would still require manually extracting the standard and runtime libraries from your bs-platform installation.
The module format is configured through the package-specs property in bsconfig.json:
{
...
"packages-specs": ["es6-global"] /* Or "es6" */
}
Having said all that, you actually can turn off exports by putting [###bs.config { no_export }] at the top of the file. But this is undocumented since it's of very limited use in practice, for the above mentioned reasons.
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"
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?