#define iTunesFileSharingEnabled... how do I declare this - xcode

I would like to create a define based on the status of iTunes File Sharing boolean status on the Info.plist file. So, I have created this:
#define itunesFileSharingEnabled [[[NSBundle mainBundle] \
objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]
#if itunesFileSharingEnabled
#define something
#endif
but the if fails with the error invalid token at start of preprocessor expression.
if I substitute #define itunesFileSharingEnabled with
#define itunesFileSharingEnabled YES
than the if compiles perfectly. So the error is on the previous line. Xcode is not liking the #define line.
What I want is to define some directive to be true if itunes file sharing is YES and NO if it is not.
How do I declare that?
thanks.
edit:
the problem is that I cannot use regular if to check for iTunes file sharing at run time because I want to make the compiler fail using #error or #warning directive...
for example, later in my code I want to use this
#if iTunesFileSharingEnabled
#error TURN OFF FILE SHARING
#endif
I want the compiler to fail if file sharing is turned on.

Preprocessor directives are evaluated at compile time.
after the first run of the preprocessor
#define itunesFileSharingEnabled [[[NSBundle mainBundle] \
objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]
#if itunesFileSharingEnabled
#define something
#endif
becomes
#if [[[NSBundle mainBundle] objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]
#define something
#endif
During the second run the preprocess tries to validate [[[NSBundle mainBundle] objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]. Which won't work because this can't be evaluated at compile time. This is a statement that can only be evaluated at run-time.
I don't know if the stuff you want to do is possible at all. (I don't know much about the preprocessor).
I guess you know already that you can do those checks at runtime
if ([[[NSBundle mainBundle] \
objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]) {
[self foo];
}
else {
[self bar];
}
Another option would be to enforce a manually entered precompiler macro
This goes into your code, somewhere were it is only called once. Probably in the init of your library:
#if HAS_ITUNES_FILESHARING
if (![[[NSBundle mainBundle] objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]) {
[NSException raise:#"MBFileSharingNotActiveButDeclaredException" format:#"File sharing is not active but \"HAS_ITUNES_FILESHARING\" is set to 1"];
}
#else
if ([[[NSBundle mainBundle] objectForInfoDictionaryKey:#"UIFileSharingEnabled"] boolValue]) {
[NSException raise:#"MBFileSharingActiveButNotDeclaredException" format:#"File sharing is active but you did not declare it as preprocessor macro. Please set \"HAS_ITUNES_FILESHARING\" to 1"];
}
#endif
This has to be entered in the Build Settings as Preprocessor Macro:
HAS_ITUNES_FILESHARING=1
If HAS_ITUNES_FILESHARING=1 is not declared in the preprocessor macro section, but File Sharing is active the code will throw an exception.
If HAS_ITUNES_FILESHARING=1 is declared, but File Sharing is not active, the code will raise an exception too.
This way you can always tell that the preprocessor macro matches the configuration. If you only call this once (in +(void)initialize there should be no performance impact at all.

Even though you can only check for it (in code) at runtime, iTunes File Sharing is something that an app developer sets in development. If you don't want file sharing, don't turn it on.
Presumably you're not actually having trouble with your own left and right hands working at cross purposes, though -- more likely you're in a situation where you're writing code (which wants iTunes File Sharing off) to be used by someone else (who might have it turned on)?
In that case, your best recourse is documentation (or licensing). Communicate to the user of your library that it should be used only in projects without iTunes File Sharing. To put it another way: if you're giving your source code to another programmer, you've surrendered control over what they do with it, but you can still give them recommendations as to how it's best used. (Or have your lawyer get them to agree to only use your software in ways that you specify, but that's no longer a programming question and this isn't a legal advice forum.)
(Aside: you could also consider doing something interesting with the build system: e.g. a shell script build phase that reads the project's main Info.plist. However, if your library is a dependency of the app, it'll need to be built first, which means that plist won't be there for it to read. Again, communication is your best bet.)

Related

How to handle CLion inspections and config files?

I'm making a firmware for an embedded device and when I build for different hardware I use different config settings.
For this I have a config file config.h:
#define FOO_MODE 7
In my code I would then use something like
void do_something_if_in_mode_4() {
if (FOO_MODE == 4)
return;
// ...
}
But CLion understands the config file as code and tells me that the "Condition is always false" and that return is unreachable code.
That file is code! The preprocessor included that file's content in your main source code and replaced all occurrences of FOO_MODE with 4. The compiler never sees FOO_MODE; remember that the preprocessor is dumb string handling that happens completely before the compiler gets to see the source code
And your compiler correctly detects the unreachable code, because 7 is not 4. The compiler will also be smart enough to omit the unreachable code in the binary, which is desirable.
If the warning annoys you, I'm sure there's ways to disable it. However, I think it's a good tool, so I'd keep it.
For code that you really do not even want to compile for some devices, try to use preprocessor #if instead, to effectively remove the text from the code that the compiler gets to see.

Find if the code under a macro is getting compiled

I have a large base of code for a series of embedded devices. Everytime we make a fix for one product, we merge-in the changes for others. Sometimes, some devices have the code under Macro's .. something like
#if DEVICE1
Do_This();
#elif DEVICE2
Do_That();
#else
Do_SomethingElse();
#endif
In the above case, I will have to merge-in the code under resspective macro. Sometimes, it is not very stright forward. So, after merging-in the changes.
During compilation time, is there any way to find whether the new added lines of code getting compiled or not?
cpp is the same preprocessor used by gcc. Call it manually with the same flags, it will output resulting (processed) code. Search interesting area to check what you want.
E.g. cpp foo.c | less.

Xcode, is it possible to intercept and change code on build without updating the file? If so, how?

I need a way to intercept the code before it goes into the compiler, change it, AND have it remain the same in the file / in Xcode afterwards.
I thought build scripts were a sort of stream interception but that doesn't seem to be the case. Another method might be to run a script both before and after build. Are there any implications with this I should be aware of?
----- EDIT -----
Why? I have an idea for an auto-logging system based on a certain comment syntax. I want to be able, on build, to parse a certain string and replace it with a logging function but have the code remain unchanged. Is it possible?
----- UPDATE -----
It seems a custom compiler might be the way forward, or at least a plugin that wraps current LLVM clang. I've been investigating this. Here's a related question for those interested: Xcode custom compiler which wraps and does a passthru to clang
If by "on build" you mean before actually compiling the code, that means you need to open Xcode every time you want to run your script. I don't believe there is a way to do this. However, you CAN use Automator to receive a string before running the code, but you would need to use Automator to build the app, which is limiting. Another method would be to make 2 classes in your app: a pre-run class and a main class. The pre-run class will prompt the user or read a file (or something like that) to get the string, and run the main class in a special way depending on the string.
Edit: response to comment
I don't know how to do this in Objective-C, but you can always rename your main file to main.mm (.mm files contain both C++ and Objective-C code) and add C++ code to it. However, this is using the Console:
using namespace std // all (this line is optional)
string s = ""; // this
cin >> s; // is C++ (if you omitted the optional line above, the correct code is std::cin >> s;
MainClass mc = //constructor for your "main class" here in Objective-C
if(s == someCertainString){ //hypothetical string and C++ condition checking for a C++ string
[mc doThisACertainWay:];
}else if(s == someOtherString){ // again, hypothetical string that you need to declare
[mc doThisADifferentWay];
}
I'm not on a PC now so I can't check code, but you can search for how to read and write to files in C++ and Obj-C. The only hint I can give right now is that you need #include <iostream> at the beginning if you use C++ to read/write the file.
If you don't want to use the console (which is normal if you wan to publish this) you can also make a dialog. In this example, you don't need C++ so you don't rename the main file. Make a new window (referred to as theDialog from now on) that is visible at start and make sure that your main graphical interface does NOT show up startup. Add a text field to theDialog and give it a name (in this example, tf). Add a label to tell the user what to put in the text field. Add a button and link it to an action. In this action, put the following code:
MainClass mc = // constructor here
NSString *str = [self.tf stringValue];
if([str equalsString:someString]){ // hypothetical string and possible error in the condition checking, I'm new to Obj-C
[mc doThisInACertainWay];
} else {
[mc doThisInADifferentWay];
}

Setting label text from other header files in Visual C++ 2010 .rc file

Assume that you have a label in a legacy Visual C++ 2010 project, defined like so:
[foo.rc]
LTEXT "Foo",IDC_STATIC,42,42,42,42
In a resource (.rc) file.
Now, you want to generate the text based on constants you define in a header file, like so:
[foo.rc]
LTEXT FOO_TEXT,IDC_STATIC,42,42,42,42
Where FOO_TEXT was previously defined in some other way, for instance:
[bar.h]
#define FROBNICATE "F"
#define OO "o"
#define ICANTTHINKOFMETASYNTACTICVARIABLESBEGINNINGWITHO "o"
#define FOO_TEXT (FROBNICATE OO ICANTTHINKOFMETASYNTACTICVARIABLESBEGINNINGWITHO)
Only that that doesn't work, because .rc files are not header files, and the RC compiler complains, telling you:
[Build output]
1>foo.rc(42): error RC2116: expecting number for ID
1>
1>
1>foo.rc(42): error RC2108: expected numerical dialog constant
What would you do?
To clarify, yes, the entire string in question is known at compile-time, but it also needs to be constructed from smaller strings (in this case, version information and release category (development, release, and another one)). Of course, I could also write C++ code that does that, but that seems very inelegant to me.
So, is there a nicer way?
I don't think you will be able to achive what you want without C++ code. See the comment to this msdn article:
Don't use parens in #define
The resource compiler is very limited in its understanding of directives. So, for example, this:
#define RESTYPE_FILE (256)
will silently get ignored, while this:
#define RESTYPE_FILE 256
will work. Obviously, trying to use expressions or anything complicated like that will silently fail, leaving you wondering why you can't load that resource.

Can’t setBounds even with NS_BUILD_32_LIKE_64 macro

My project compiles and runs OK in debug mode, but when I switch to release x86_64 compiling, I get compiler errors for attempts to setBounds using NSRect. (The errors read “incompatible type for argument 1 of setBounds”.)
There are lots of posts which I take to be suggesting to add the NS_BUILD_32_LIKE_64 macro definition above the Cocoa (Foundation) import, so that the “if NS_BUILD_32_LIKE_64” language in NSGeometry.h will be true and the necesseary typedefs will be used. So I added the macro definition to the h file of the offending class:
#define NS_BUILD_32_LIKE_64 1
#import <Cocoa/Cocoa.h>
And I still get the same compile errors.
I also tried converting explicitly from NSRect to CGRect, so that instead of this . . .
// rectIncomingSource is an NSRect
calayer.bounds = rectIncomingSource;
. . . I wrote this:
calayer.bounds = CGRectMake(rectIncomingSource.origin.x, rectIncomingSource.origin.y, rectIncomingSource.size.width, rectIncomingSource.size.height);
Same errors.
And why would setting bounds be the only problem? Per Apple docs, NSInteger and NSUInteger are the main conversion problem, and I use them all over the place, but the compiler doesn’t complain about them. So why would it choke on bounds?
I’m probably missing something really simple here — for which I apologize to the wizards. Any help for the blind?
The target info window gave me the clue to figure this out:
I was putting the NS_BUILD_32_LIKE_64 define in a particular class's h file. It should have been in the prefix header file, the one with the pch extension that usually resides in the project's "Other Sources."
#ifdef __OBJC__
#define NS_BUILD_32_LIKE_64 1 // this line added
#import <Cocoa/Cocoa.h>
#endif
Well, yeah, I suppose this was obvious. But maybe some other preprocessor neophyte will find this clarification helpful, so I won't delete the question.
And I still don't understand why setting bounds should have been the only problem. Maybe something to do with core animation?

Resources