How can I use a preprocessor macro in an #import directive? - c-preprocessor

Our company's main project has several preprocessor constants that must be adjusted for different customers. When the program was first written, it was considered enough to merely to build Debug and Release versions of the code. It never occurred to anyone until I got tired of rebuilding the project all the time that we could use preprocessor constants and project settings to build into different folders for each customer.
But we have one ActiveX DLL our project needs that has to be in a specific folder. (Making that an ActiveX DLL was yet another in the long list of bad decisions my company made on this project.) That DLL is #imported into the code using this:
#ifdef _DEBUG
#import "..\Debug\CapsHelper.dll" no_namespace
#else
#import "..\Release\CapsHelper.dll" no_namespace
#endif
I am currently trying to build for a customer named Algoma. So, I want to create a preprocessor constant named CUSTOMER that would contain "Alcoma" and then tell the compiler to import from a folder named either "Debug Alcoma" or "Release Alcoma". How would I do that?
I tried this:
#define CUSTOMER Alcoma
#ifdef _DEBUG
#import "..\Debug " #CUSTOMER "\CapsHelper.dll" no_namespace
#else
#import "..\Release " #CUSTOMER "\CapsHelper.dll" no_namespace
#endif
But that didn't work. It didn't work without the # before CUSTOMER either.

I presume you're using MSVC, and I haven't tested this solution with it. But it should work:
#define XSTR(X) #X
#define STR(X) XSTR(X)
#ifdef _DEBUG
#import STR(..\Debug CUSTOMER\CapsHelper.dll) no_namespace
#else
#import STR(..\Release CUSTOMER\CapsHelper.dll) no_namespace
#endif
The basic issue with your attempt (aside from the fact in standard C/C++, # can only occur inside a macro expansion) is that while #include (and, I suppose, #import) will macro-expand their argument, they will not perform string concatenation. So the stringify operator needs to be applied to the entire string.

Related

Prevent inclusion of headers into same file in C

I'm looking for a way to enforce that certain headers cannot be included into the same file.
To explain the situation further, assume I have the headers
a_1.h, b_1.h
and
a_2.h, b_2.h
I want to prevent the inclusion of _1 and _2 files into the same file, regardless of if they were
a_ or b_
Assuming that mixing the _1 and _2 headers is a mistake that needs to be caught, a simple way of catching it is to define and check guard macros to check for mixed usage of these headers and use the #error directive to report errors.
For example, the a_1.h header can include this code:
#ifndef A_1_H__INCLUDED
#define A_1_H__INCLUDED
/* Define header set as 1 if not already defined. */
#ifndef HEADER_SET
#define HEADER_SET 1
#endif
/* Check for consistent header set usage. */
#if HEADER_SET != 1
#error "Inconsistent header sets"
#endif
/* Other header stuff ... */
#endif /* A_1_H__INCLUDED */
The other headers will be similar but the _2 headers will have #define HEADER_SET 2 and #if HEADER_SET != 2.
Remember that ANY other file in the build process can include a header. With the typical include guard: #ifndef MYHEADER \n #include MYHEADER, the header code is only inserted on the first instance. After that, the compiler has eaten it and remembers and doesn't need to include it again. Think of compiling as putting ALL the source code into one file and turning that into a binary. (you know, "compiling" as in putting it all in a pile). So it's not "into the same file" it's "into the same build".
You want a header file to be mutually exclusive with another header file. (Like, say, if you've got code that targets specific hardware via includes, and you obviously can't build towards two chips at the same time.) First off, if that's an issue, you should really have a single place where such things are defined (like the build script) so that's not a problem. But if you want a simple safeguard:
#ifndef PPC_e6500
#define PPC_e6500
#ifdef LINUX
#error This processor ain't big enough for the both of us, Tux. This here's 8548 territory!
#endif
That will fail to build and you can figure out who did whatever horrible thing that tried to build towards two targets at once.

How can I compile two version of my code in IAR Embbedded Workbench

I have two version of code and I need to switch them as work need to compile each one while keeping two version on an IAR project. I find something like "compile switch" but I don't know how is it doing. Is there anyone tell me a keyword or an advice that can I search?
You can use C preprocessor #define feature to toggle between code versions and use IAR EWARM project's Defined Symbols feature to enable a list of #defines in a specific header file (for example: defines.h) that will be included in all C files.
defines.h
#if defined(PROD_VERSION)
#define SOFTWARE_VERSION_PRODUCT ("1.0-release")
//...whetever specific #defines meant for the release version, for example...
//#define ENABLE_RF_STUB
#define USE_SERIAL_CTS_RTS
#elif defined(TEST_VERSION)
#define SOFTWARE_VERSION_PRODUCT ("1.0-test")
//...whetever specific #defines meant for the test version, for example...
#define ENABLE_RF_STUB
#define USE_SERIAL_CTS_RTS
#elif defined(DEBUG_VERSION)
#define SOFTWARE_VERSION_PRODUCT ("1.0-debug")
//...whetever specific #defines meant for the debug version, for example...
#define ENABLE_RF_STUB
//#define USE_SERIAL_CTS_RTS
#endif
in rf.c
#include "defines.h"
void rfInit(void)
{
#ifndef ENABLE_RF_STUB
//init RF here
#endif
}
In serial.c
#include "defines.h"
CPU_BOOLEAN isCtsRts()
{
#ifdef USE_SERIAL_CTS_RTS
return HAL_SERIAL.isCtsRts();
#else
return DEF_TRUE; //bypass CtsRts check
#endif
}
In your project option > C/C++ Compiler > Preprocessor > Defined symbols: add PROD_VERSION if you want the release version, or add TEST_VERSION if you want the test version or add DEBUG_VERSION if you want the debug version.
You can only choose one of the three configurations above only as IAR will only compile one version via the project compilation. Unless you can create a batch build script to allow building all the three versions under different output files created with three different project setups.
IAR has a configuration in toolbar Project > Edit_Configuration
It makes you set version "switches" via set these tool and it is possible to set preprocessor command for each setup.

Switching between implementations in C precompiler

I'm fairly new to programming in C. My problem is that I have two implementations of a function and I want to be able to switch between them easily.
Right now I define the two implementations of the function as function_implementation1 and function_implementation1 in the files "funtion_implementation1.h" and "funtion_implementation2.h" respectively. To switch between them I have the following file:
#define IMPLEMENTATION1
#ifdef IMPLEMENTATION_1
#include "funtion_implementation1.h"
#define myFunction function_implementation1
#endif
#ifdef IMPLEMENTATION_2
#include "funtion_implementation2.h"
#define myFunction function_implementation2
#endif
In order to switch from one implementation to the other I just have to change the first line. This approach works, and I was satisfied with it for a while, but now it is bugging me that I have to open this file so often. I have a parameters.h file where I define all my parameters and I would rather choose which implementation to use in that file. Sadly, moving the first line to that file does not work. If I do that myFunction is not defined.
What is the best way to do this?
you should include your parameters file where you use alias, macros, etc:
#include "Parameters.h"
also, all your headers files should start with:
#ifndef __FILE_H__
#define __FILE_H__
// definitions go there
#endif
This prevents nested include of header files
Use preprocessor options, specifically the -D option. If you wanted to use IMPLEMENTATION1, when you are compiling that file on the command line (or in IDE), add -D IMPLEMENTATION1. This defines that macro. Same works for any macro

What is the purpose of "__SRCVERSION" function at the end of each C file?

I am working on the source code of a Unix-based kernel. I noticed that the last line of each source code file (.c or .h) is a specific line with the following format:
__SRCVERSION( "$URL: ... $ $Rev: 219996 $" )
The URL points to the web address of the same file. I'm wondering what does that mean, and what is it actually for? Would it be any problem if I delete this line from all of my source code files?
Macros like this are often used to embed versioning information into binaries when they are compiled. They can be updated automatically when fetched out of a source control system with appropriate rules. Removing them shouldn't cause any harm, but you will lose the benefit of being able to search a binary to identify which versions of your source files were used to compile it.
As #Keith Thompson says below, it may also be possible to configure your build to not embed the information. Below is an example of the macro definition taken from here (different systems are likely to have different definitions). You can see that it uses the __USESRCVERSION definition to decide which version of the __SRCVERSION macro is used:
#ifndef __USESRCVERSION
#define __SRCVERSION(id)
#else /* __USESRCVERSION */
#ifdef __QNXNTO__
#if defined __SRCVERSION
#undef __SRCVERSION
#endif /*__SRCVERSION */
#define __SRCVERSION(id) \
__asm__(".section .ident,\"SM\",#progbits,1"); \
__asm__(".asciz " #id); \
__asm__(".previous");
#endif /* __QNXNTO__ */
#endif /* __USESRCVERSION */

How do I get a bundle reference from inside of a plugin with carbon?

I'm writing a C++ plugin in Mac OS X using the Carbon framework (yeah, yeah, I know, Apple is deprecating Carbon, but at the moment I can't migrate this code to Cocoa). My plugin gets loaded by a master application, and I need to get a CFBundleRef reference to my plugin so that I can access it's resources.
The problem is, when I call CFBundleGetMainBundle() during my plugin's initialization routines, that returns a reference to the host's bundle reference, not the plugin's. How can I get a reference to my plugin's bundle instead?
Note: I would rather not use anything determined at compile-time, including calling CFBundleGetBundleWithIdentifier() with a hard-coded string identifier.
See this posting on the carbon-dev mailing list, which seems to be a similar situation.
The method given there is
I recommend using CFBundleGetBundleWithIdentifier.
Your plug-in should have an unique identifier; something like
"com.apple.dts.iTunes_plug-in", etc. Look for the CFBundleIdentifier
property in your plug-in's bundle's info.plist.
Note: I would rather not use anything determined at compile-time, including calling CFBundleGetBundleWithIdentifier() with a hard-coded string identifier.
Because that's WET, right?
Here's how you can make that solution DRY.
First, define some macros for this in a header file, like so:
#define MY_PLUGIN_BUNDLE_IDENTIFIER com.example.wiflamalator.photoshop-plugin
#define MY_PLUGIN_STRINGIFY(x) #x
#define MY_PLUGIN_BUNDLE_IDENTIFIER_STRING MY_PLUGIN_STRINGIFY(MY_PLUGIN_BUNDLE_IDENTIFIER)
Import the header file into the code that calls CFBundleGetBundleWithIdentifier. In that code, use CFSTR(MY_PLUGIN_BUNDLE_IDENTIFIER_STRING).
Then, in Xcode, either set that file as your Info.plist prefix header, or (if you already have one) #include it into that header. Finally, in Info.plist, set the bundle identifier to MY_PLUGIN_BUNDLE_IDENTIFIER (in a string value, of course).
Now you have the bundle identifier written in exactly one place (the header), from which the C preprocessor puts it in all the places where it needs to be, so you can look up your own bundle by it using CFBundleGetBundleWithIdentifier.
#ifdef __APPLE__
#include "CoreFoundation/CoreFoundation.h"
#endif
#ifdef __APPLE__
// This should be actually defined somewhere else
#define MY_PLUGIN_BUNDLE_IDENTIFIER com.yourbundle.name
// Then all the regular stuff
#define QUOTE(str) #str
#define EXPAND_AND_QUOTE(str) QUOTE(str)
#define MY_PLUGIN_BUNDLE_IDENTIFIER_STRING EXPAND_AND_QUOTE(MY_PLUGIN_BUNDLE_IDENTIFIER)
CFBundleRef mainBundle = CFBundleGetBundleWithIdentifier(CFSTR(MY_PLUGIN_BUNDLE_IDENTIFIER_STRING));
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
char path[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
{
// error!
}
CFRelease(resourcesURL);
chdir(path);
StoragePaths::setApplicationResourcesDirectory(STR(path));
#endif
Prints the path to the your bundle
Note: For JUCE users, use JucePlugin_CFBundleIdentifier instead of MY_PLUGIN_BUNDLE_IDENTIFIER and you're all set

Resources