April 27, 2024, 02:31:04 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Compiler Options -Define

Started by LarryMc, January 08, 2013, 09:45:50 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

I'm currently working on the new help manual; the section about setting compiler options.

I'm currently working on the Define page of the multipage Compiler Options dialog.
The existing docs say it does the same thing as the command line /D option which in turn says it is for defining constants with or without a value.

I don't know about everyone else but that really doesn't tell me much.
The dialog page allows the user to enter a variable name and a value.
Once entered the variable can be selected and edited(both the name and the value.)
So, this is what I figured out.
1. the variable is a constant which can't be changed inside your program.
2. the value, if entered, must be a interger.  If you enter 13.7 it will be evaluated as 13
3. the constant is project global in nature.

With a value entry (assume name entry is c2xyz and value is 17):
1. constant can be tested anywhere in the source code with
IF c2xyzor
IF c2xyz = 17
or
Select c2xyz
   case 17
and similar ways.
2. if you try to assign a value to the constant in the source it will cause a compiler error.
3. the constant can be tested, ignoring any value, with
$IFDEF c2xyz
and similar statements

Without a value entry (assume name entry is c2xyz and no value ):
1.Trying to use an IF or SELECT statement will result in a compiler error.
2. the constant can be tested with
$IFDEF c2xyz
and similar statements

Another important aspect is that each entry in the Define page has an associated check box associated with it.
Checking a box means the constant will be created in the subsequent compiles.
Unchecking means the constant will not be created for the current compile.
(while checking this out I just discovered a bug in my routine for updating the options in the ini file)

Now, the big question is why would someone want to use this feature.
Let's say we're working on a large project that has 50+ source files.
Let's say we want to have 2 versions; one full featured for beta testing and one that has certain functions disabled to give away freely as a demo.
Sound familiar? ;D
The simple thing to do is create a single global variable and set it to 0 for demo and 1 for full program at the beginning of the program.
Then we load up all the source files with a bunch of IF states to skip over the parts of the code we want disabled in the demo.
We then compile the two different versions.
There's a significant problem with this technique.
ALL the source code for the FULL program is compiled and exists in both versions of the exe.
All a hacker needs to do to change the demo exe into the fully functional version is find the one memory location and change a zero to a one.
That would take a rookie hacker maybe 10 minutes.

The best way to create the demo version is to not have any of the compiled code you want disabled in the exe.

One possible solution is to maintain two separate projects with different source files. This is really not an option because trying to maintain both will be next to impossible to do in a reliable manner for larger projects.

The preferred solution would be to used conditional compiling.
Conditional compiling involves the use of preprocessor directives inserted in the source files and responded to by the compiler.
To do this we first define a constant which needs to be unique to the project.
This is done like this:
$DEFINE DEMO_VERthen we set up the areas we want to protect like this:
$IFDEF DEMO_VER
   sub compile()
      'this is call a stub file
      messagebox 0, "Feature not available in demo version","Demo Version",0
      return
   endsub
$ELSE
   sub compile()
      'this is the full code version
      blah,blah,...
      return
   endsub
$ENDIF


When we define a constant using the $DEFINE directive it is global to the source file it is contained in.
It has to be defined in each source file it is tested in.
Obviously we dont want to have to define it in 50+ source files and then have to modify each source file each time we want to switch between compiling a full or demo version.
The solution is easy.  We put the $Define statement in an include file and then include the inc file into each of the source files.
Now when we want to switch between compiling the two versions we simply open the inc file and add/delete a ' in front of the $DEFINE.

With the above setup a hacker doesn't have any code to hack and activate because the code is never in the demo version.

Next question... So what does an entry in the Define page do for us.
Any entries in the Define page are automatically project global.
That eliminates the need for the include file entries.
By clicking the associated check box for an entry the user can switch between demo and full version for subsequent compiles.

I'm using 2 levels; demo and full. But using this technique there is no limit to the versions you could have.
IWBDemo, IWBStudent Demo, IWBFull, IWBStudentFull, AuroraDemo, AuroraStudent Demo, AuroraFull, AuroraStudentFull,etc
..notice the addition of Aurora because I think a slightly different version of the new IDE would work there also. ;)
and I've got my eye on CB if LarryS can figure out a couple of things for me.

Anyway, I hope the preceding will shed a little more light on the feature.
I will try to explain it better in the help file.
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

Continuing with the thought of one set of source files for multiple projects.
When building a project you can have resources in a resource file.
The resource file HAS to be named the same as the executable file but with a .rc extension.

So, using what has previously been discussed how can we make all this work when we need to account for different versions of the application possibly having different variations of the resource file.
To begin with we don't want to maintain 4-5 different versions of the rc file (making a global type change would require modifying all the rc files.
So how do we get arounf the naming issue for multiple projects and only having to worry about updating one rc file.

A review of the resource compiler help file tells us:
1. the rc files can have an #include statement that looks and works pretty much like IWB's $include statement.
2. rc files can have #define statements that are like IWB's $define
3. and rc files have the #if / #elseif / #else / #endif preprocessor statements like IWB has.

So, here's what we do
1. Create a master.rc file that contains all the resources.
2. Create 4-5 different rc files with names that match the exe files for each of the different projects
    These rc files will basically contain two lines of code
    1) #define projver= {1,2,3,4,5} (one number to identify which project)
    2) #include "master .rc"
The master.rc file will have #if statements, testing the value projver, in order to know what to include/exclude in a particular project.

So, in essence, we are doing in the rc file exactly what we are doing in the main source files.
In the future, with this setup, I will only have to modify one rc file when any changes are required.

And,FYI, I am using this same technique in the inno setup installer so that I can create installers for all the versions with just one source file.

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library