Can I undefine a conditional in the command line? - delphi

In the help of Delphi 7 command line compiler, I just see an option to define a conditional compiling directive:
-D<syms> = Define conditionals
Is it possible to undefine a conditional?
I have defined DEVELOPMENT in the IDE, and want to have define just PRODUCTION in the command line compiler. The problem is that the command line compiler keeps the IDE definitions. I'd like just to undef it as is possible in the C world.

If you don't come up with a command line option, you can always add additional conditionals in your units or include file like this:
{$DEFINE FOO}
// Allow us to undefine foo at the command line by defining UNDEFFOO
{$IFDEF UNDEFFOO}
{$UNDEF FOO}
{$ENDIF}
{$IFDEF FOO}
...
{$ENDIF}
Then use -D to set UNDEFFOO.

You can use {$UNDEF NAME} to undefine a symbol, equivalent to #undef in C and C++. The facility to undefine a conditional is only applicable at a unit level and cannot be applied project wide. In other words you cannot unset conditionals at the command line. This is no different from the facilities offered by C or C++ toolsets.
A very common approach is to locate all your conditional definitions in a shared .inc file which is then included at the head of every source file that relies on those definitions. If you arrange things this way then you have all the flexibility that you need.
I know it will be of little consolation, but more recent Delphi versions have much stronger support for configuration management. Modern Delphi versions make use of the msbuild system. They allow the same configuration options to be used in the IDE and on the command line. There is flexibility to define, for example, debug and release build options and switch between them easily. I know I find it a great reassurance to know, for sure, that I am using the same build in the IDE as on the command line. I did not feel anywhere near so secure in legacy Delphi versions.

Related

Defining preprocessor symbols for CLion analyzer

In my project there's a file enclosed in an ifdef preprocessor directive
#ifdef SOME_SYMBOL
... entire file ...
#endif
SOME_SYMBOL is defined by another file that's compiled before this one, and the code works as expected, but the static analyzer isn't aware of this symbol and so it treats SOME_SYMBOL is undefined. The entire file has no syntax highlighting and some of the analysis is just skipped (e.g. syntax error highlighting).
Is there a way to tell the analyzer to treat this symbol as defined without defining it in CMakeLists.txt?
I don't have the option of defining SOME_SYMBOL in CMakeLists.txt since the project depends on it being undefined in some compilation paths (changing this would be near impossible).
Update:
Seems like this is currently an open issue with JetBrains. See Issue CPP-2286
Clion now has a macro which you can use to detect the IDE:
https://youtrack.jetbrains.com/issue/CPP-1296#comment=27-1846360
#ifdef __JETBRAINS_IDE__
// Stuff that only clion will see goes here
#endif
This allows you to put in defines to make clion render your code properly in cases where it can't be clever enough to figure it out.
The __JETBRAINS_IDE__ macro's value is a version string for the IDE. Specific versions of the macro exist for different Jetbrains IDEs: __CLION_IDE__, __STUDIO_IDE__ (for Android Studio), and __APPCODE_IDE__ (for AppCode).
Yay!
To get syntax highlighting:
Go to Settings ⇒ Editor ⇒ Colors&Fonts ⇒ C/C++ and remove all ticks for 'Conditionally non-compiled code'. This way all code will show up with the usual highlighting.
The task has no solution for common case.
But! You can find the target and related resolve context, where SOME_SYMBOL is defined.
...in the status bar you can find the Resolve Context chooser for switching between the Debug, Release, RelWithDebInfo and MinSizeRel contexts to resolve your code in the IDE with the desired definitions.

Compiler Directive IF and IFEND

I have a project group containing three projects (two exe and one dll). Now, in one unit which is shared by the two exe-projects, I want to compile a specific region ONLY when in a specific project. How can I achieve this? Should I do something like this?
{$IF PROJECT1}
// Compile this code
{$IFEND}
I have never used Delphi compiler directives before.
Compiler directives are defined at the project level (Project > Options > Delphi Compiler > Compiling), so as long as you do define the directive, it should work as you describe.

How to set ISPP defines based on default Inno Setup variables?

I was trying to:
#define CommonAppData {commonappdata}
but it yields:
Compiler Error
[ISPP] Expression expected but opening brace ("{") found.
How to achieve this with Inno Setup PreProcessor?
{commonappdata} cannot be expanded at compile time, i.e. when the pre-processor runs because it is only known at runtime: It identifies the common application data directory on the machine where the compiled installer is run.
Maybe if you could clarify how you intend to use that define we might be able to help. If for example what you're really interested in is not the common app data directory on the target machine but the one on the developer machine, then you can probably use this:
#define CommonAppData GetEnv("COMMONAPPDATA")
If however you intend to use that define for populating Inno properties that are themselves capable of expanding the constant at runtime then you should use this:
#define CommonAppData "{commonappdata}"
Hope this helps.
#define is a inno setup pre-processor directive, in a pre-compile phase. It works much like a C pre-processor.
By defining a pre-processor variable, we force the compiler to see a script after the ispp defines are resolved:
Inno Setup Preprocessor (ISPP) is an add-on for Jordan Russell's Inno Setup compiler. More technically speaking, it is an additional layer between GUI (your Inno Setup script) and the compiler, which before passing the text intercepts and modifies it in a way it is told by using special directives in the script text.
That said, I can't find a source in documentation nor have time to digg into the source code, but I'm pretty sure inno setup variables are not available during this pre-compile time.
If you just want the defined variable to contain the string {commonappdata}, use it directly in your source... if you want the defined variable to have the run-time value of commonappdata, it doesn't seem possible to me, because that value is determined at runtime as its current value depends on the target machine (windows version, language, etc.).
If you think it twice, it doesn't make sense to try to use that value at pre-compile or compile time... this is just the whole fact that brings inno setup constants like {commonappdata}, {destdir} and the like to existence... that you can express in a standard way at compile time a unknown but meaningful value, which will be known and evaluated at runtime.
You'll probably need to escape the brace. Something like:
#define CommonAppData {{commonappdata}

Where do I define symbols tested with {$IFDEF}?

When I use Delphi directives in code, like:
{$IFDEF something}
.
.
.
{$ENDIF}
Where do I assign the word 'something' in the project? I tried in some places in project options but it didn't work. Guess I didn't find the correct one.
It's in the Conditional Defines slot under Project | Options, which looks like this on D2010:
Other answers have pointed you at the places to define symbols and the scope implications of the different approaches.
However, what no-one has yet mentioned is that if you change the DEFINE symbols you MUST do a FULL BUILD of your project for them to have any effect on your code.
When you "Compile" the Delphi compiler will only compile units which have themselves changed since the previous compile. If you change DEFINE symbols this doesn't change any project units, so if the units are not re-compiled then the change in DEFINE symbols will not have ANY effect in those units.
To FORCE changes in DEFINE symbols to be applied in ALL units, you MUST "build", not compile.
This may explain why your attempt to set defines did not appear to work previously
You can also define them in {$DEFINE <symbol>} directives. What changes is the scope. When you define a <symbol> under conditional defines in the project options, the scope is global to the whole project. $DEFINE directives are valid only from the point they are declared to the end of the current module, or until an $UNDEF directive using the same <symbol> is encountered. What to use depends on your needs, and what the IFDEF does.
There are two places where you can put conditional defines that are used in all units of a project:
in the project options (as David Heffernan already said)
in an include file that is included in all of these units
Why do I mention the second option? Because it allows specialized processing based on the VERxxx conditional define and other conditional defines given in 1. See jedi.inc (from the Jedi JCL) for an example.
Also, as Deltics said: When it determines which units to recompile, the compiler only checks whether the unit itself has changed, not whether the conditional defines or any include files have changed. So if you change conditional defines, you must do a rebuild, not just a recompile. Since the Delphi compiler is very fast, this fortunately does not make much of a difference for compile times.
You can define global symbols in external file with .inc extension.
Create a new text file, put in it all you defines and save it as for instance Predefines.inc:
--- Content of the file Predefines.inc ---
{$DEFINE Symbol}
{$IFDEF Symbol}
{$DEFINE AnotherSymbol}
{$ENDIF}
In you Delphi modules, where you need to check are symbols defined, put this code in interface section:
interface
{$I Predefines.inc}
uses ...
// Check you defines
{$IFDEF Symbol}
...
{$ENDIF}

Including client files for shared file

Okay, so I have 2 projects for a game. One is the server and one is the client. I keep the shared units into a shared folder that I use to include in my client/server project. There is a problem however: I have a shared file that needs a different file for client / server. Example: mySharedLib needs to print to the console, however the client/server console is different. What are my options? Thanks
In your shared file you could use define compiler directive
For example
{$IFDEF MYSERVER}
Writeln('Server'); // this code executes
{$ELSE}
Writeln('Client'); // this code does not execute
{$ENDIF}
Then in your server project define a MYSERVER define and in your client define a MYCLIENT one, then when the shared code seperates use an {$IFDEF) statement.
From the Delphi help on conditional definitions:
The conditional directives $IFDEF, $IFNDEF, $IF, $ELSEIF, $ELSE, $ENDIF, and $IFEND allow you to compile or suppress code based on the status of a conditional symbol. $IF and $ELSEIF allow you to base conditional compilation on declared Delphi identifiers. $IFOPT compiles or suppresses code depending on whether a specified compiler switch is enabled.
This will not however work if the shared code is in a DLL or any other sort of complied shared resource such as a package.
From the Delphi help on conditional definitions:
Conditional definitions are evaluated only when source code is recompiled. If you change a conditional symbol's status and then rebuild a project, source code in unchanged units may not be recompiled. Use Project|Build All Projects to ensure everything in your project reflects the current status of conditional symbols.
If they're different, they're not really a shared file anymore.

Resources