View previous topic :: View next topic |
Author |
Message |
nikolai
Joined: 28 Apr 2010 Posts: 5 Location: Houston
|
Command line parameters with preprocessor defines |
Posted: Mon Oct 21, 2013 1:19 pm |
|
|
I have an application that I maintain for different versions of hardware. Essentially there are preprocessor define statements throughout the code that control what code is compiled for each hardware type. In the past, I would have to manually comment out the #DEFINE statements and compile within MPLAB for each build type. I'm trying to automate this by building all of the output files sequentially using a Powershell script.
I already know that I can define a preprocessor variable in the command line like this:
CCsc +FH +DH +LN +T +A +M -Z +Y=9 +EA `#FILENAME=$somevariable main.c
This also works if I save the arguments as a string.
$arguments = "+FH +DH +LN +T +A +M -Z +Y=9 +EA `#FILENAME=$somevariable main.c"
start-process Ccsc $arguments
The problem is that I have addition variables that I want to declare in the command line which don't hold a value.
CCsc +FH +DH +LN +T +A +M -Z +Y=9 +EA `#FILENAME=$somevariable #TYPE= #DEBUG= main.c
When I look in main.esym, I can see that the DEBUG variable is not defined and that TYPE=" #DEBUG". So it's just grabbing the next value in the list in the assigment. In main.esym those variables would otherwise be defined as TYPE="" and DEBUG="". But it doesn't seem to compile if I just put double quotes in the string, even if I escape them from Powershell interpretation. I'm not sure if this is a PS quirk or the compiler (v4.109). |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Mon Oct 21, 2013 1:43 pm |
|
|
Needs inverted commas.
Syntax is:
#FRED="TRUE"
To set the #define 'FRED' to the value 'TRUE'
etc..
Obviously though this gets overridden if there is a #define for FRED in the code.
Unless you want to define it as having a value, there is no point in defining it. So empty inverted commas make no sense.
Best Wishes |
|
|
nikolai
Joined: 28 Apr 2010 Posts: 5 Location: Houston
|
|
Posted: Mon Oct 21, 2013 2:22 pm |
|
|
I've tried defining them with values and they don't get detected by the #ifdef statements in the code. When I did this manually my code would look like this:
#define TYPE
#ifdef TYPE
do something
#else
do something else
#endif
But if I define them as anything at all in the command line or the code (i.e. #define TYPE 1), the #ifdef evaluations don't work. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Mon Oct 21, 2013 2:57 pm |
|
|
You need to understand the limitations of the Windows command line. This is why it works from @ file (where these limitations do not exist), and why it has to assume that the data after the =, is what is meant to be put into the define, unless a inverted comma 'value' is present.
I don't know what you are doing wrong, but a simple test, with:
CCSC main.c #test="TRUE"
and a simple block of code as:
Code: |
#ifdef TEST
delay_us(10);
#else
delay_us(20);
#endif
|
compiles to produce:
Code: |
.................... #ifdef test
.................... delay_us(10);
000F: MOVLW 10
0010: MOVWF 77
0011: DECFSZ 77,F
0012: GOTO 011
0013: NOP
.................... #else
0014: GOTO 00F
.................... delay_us(20);
.................... #endif
|
in the lst file, while removing the #TEST="TRUE", gives:
Code: |
.................... #ifdef test
.................... delay_us(10);
.................... #else
.................... delay_us(20);
000F: MOVLW 20
0010: MOVWF 77
0011: DECFSZ 77,F
0012: GOTO 011
0013: GOTO 014
0014: NOP
|
Correctly switching what is compiled. Even just using #test=" " (with a space), happily switches....
Simplify a bit and try a test like this.
I've used this on many occasions to give different version programming, without problems.
Best Wishes |
|
|
nikolai
Joined: 28 Apr 2010 Posts: 5 Location: Houston
|
|
Posted: Tue Oct 22, 2013 8:00 am |
|
|
As expected I made a stupid error. I had an #endif commented out and all of the defines below it weren't being detected. No initializing the variables in the command line to ANY value works as expected now.
Thanks |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Oct 23, 2013 2:04 am |
|
|
I haven't used any command line tools for nigh on 15 years. I never saw the attraction with remembering tens of often non-intuitive options and arcane syntax. I'd much rather get an IDE to deal with that for me. That said, I do face the same sort of issues in my compilations. I have code that, through conditional compilation, compiles to several targets. Heck, in the mainframe/mini era it was often used to build operating systems. My first exposure to the technique was in sysgen'ing RT-11 and RSX-11M.
What I do is not try to control the compilation through options, i.e. defines, in the project options/command line/build script. Instead I have a wrapper C file for each target which simply has the relevant defines and possibly includes and then includes the top level code of the generic codebase. With this you simply build the required wrappers. All the options are in the actual source code, and not in a somewhat ephemeral project/build script, and therefore can be secured in a CVS more simply (as its C code not some version/environment/user specific script file in some relatively obscure and unfamiliar syntax that cannot easily be ported to any other compilation environment, or in may cases to another PC, or even to another location on the SAME PC!)
I also prefer self-selecting includes to implement optional functionality. This is where the include has a define to show its present, which is used in the main code to activate the calling code for the functionality. So whether the function is included in the target or not simply comes down to whether the relevant code/header was included or not. Something like:
Code: |
// in application code.
// To turn off run time logging simply uncomment this include.
#include "Run_Time_Logging.c"
...
#ifdef RUN_TIME_LOGGING
Save_Run_Times();
#endif
// Run_Time_Logging.c
#define RUN_TIME_LOGGING
...
void Save_Run_Times(void)
{
...
}
|
|
|
|
|