Including client files for shared file - delphi

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.

Related

Delphi {$INCLUDE filename} in uses part of dpr file

I have many Delphi 10 projects that are using the same units, let's call them "commons".
When I add anew unit to commons, I have to manually add it to each project. I have tried adding a {$INCLUDE commons.inc} line into the uses part of each .dpr file:
uses
Forms,
{$INCLUDE commons.inc}
projectUnit1,
...;
commons.inc has this content:
common1,
common2,
I can compile a project but cannot manage the units from commons.inc. By manage, I mean Ctrl-F12, remove from project, etc.
This is from Delphi's help:
There is one restriction to the use of include files: an include file can't be specified in the middle of a statement part. In fact, all statements between the begin and end of a statement part must exist in the same source file.
I suppose that is why my idea does not work?
Am I doing something wrong, or is there another solution?
This workaround might suit. The only downside I have found so far is that the included files do not appear in the Project Manager.
Add the folder(s) containing the files to be included to the search path of every project.
Create Include.pas, a normal .pas file, and include it in the normal way in every project.
Add the files to be included in multiple projects to the uses clause of Include.pas. $IFDEFS can be used if required.

How to define and use precompiled variable in delphi directives

I want to define a precompile string variable and use it in {$include} directive in delphi, for example:
{$define FILE_NAME "lockfile"}
{$include FILE_NAME'.txt.1'}
{$include FILE_NAME'.txt.2'}
...
For security reasons (this is part of our licensing system), we don't want to use normal strings and file reading functions. Is there any capability for this purpose in Delphi?
The $INCLUDE directive does not support indirection on the file name. So, the following code:
const
someconst = 'foo';
{$INCLUDE someconst}
leads to the following error:
F1026 File not found: 'someconst.pas'
If you must use an include file, you must apply the indirection by some other means. One way could be to use the fact that the compiler will search for the included file by looking on the search path. So, if you place each client specific include file in a different directory, then you can add the client specific directory to the search path as part of your build process.
FWIW, I find it hard to believe that this will make your program more immune to hacking. I think that a more likely outcome is that your program will be just as susceptible to hacking, but that it will become much more difficult and error prone for you to build and distribute the program.
You requirement may be better satisfied by the proper use of a VCS system. You need "branches" for every customer where customer-specific files contains customer-specific data. This will avoid to litter your code with complex directive to manage each customer - file names stays the same, just their content is different in each branch. Adding a new customer just requires to create a new branch and update files there.
Then you just need get each branch and compile it for each customer to get the final executable(s) with customer specific data built in.

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.

Is it possible to find out position of a unit in project's uses clause?

I have two units (SuperPuper.pas and SuperPuper777.pas) in a project (.exe or .dll)
Is it possible to find out at runtime from my code in SuperPuper777.pas that
SuperPuper.pas is listed in project's uses clause;
SuperPuper.pas is first unit in project's uses clause.
The question was heavily edited. I guess that it's practical purpose is to find out if ShareMem.pas unit was declared in right position in project's uses clause.
If you want to enforce the correct declaration of a unit in a project's uses clause I would add a pre-build event to run a regex based Perl/Python/Ruby script. The script would do a simple regex based check of the .dpr file and return an error if it was not as intended. Not fool-proof, but probably the best balance of utility for a small amount of effort.
I realise that your question asks for runtime detection but this is a compile time property and so best attacked at compile time.
You can get a list of all units linked to the executable (i.e. at runtime) from the resources. There is a resource named PACKAGEINFO which contains a list of all units. You can find some reverse information from here. Perhaps you can get this information from enhanced RTTI (available since Delphi 2010).
About how to detect that an unit is first in the .dpr uses clause, I do not see any way of doing it at runtime easily. The list in PACKAGEINFO is not in this order. You can do that at compile time, by parsing the .dpr content and checking its uses clause.
The only way I see to guess which unit was first set is to use a global variable in a common unit:
var LatestUnitSet: (oneUnit, anotherUnit);
Then in the initialization section of each unit:
initialization
LatestUnitSet := OneUnit;
...
initialization
LatestUnitSet := anotherUnit;
...
Then check for LatestUnitSet to see which one was initialized the latest.

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}

Resources