Recent

Author Topic: Sharing same source file in two projects  (Read 9407 times)

alpine

  • Hero Member
  • *****
  • Posts: 1038
Sharing same source file in two projects
« on: October 03, 2021, 11:05:01 am »
Recently, I've bumped in a subtle issue with a shared source files.

I have two different projects in the same directory. They shared almost all their source files (also in the same directory) but two of them: the lpr and the main pas file for each project. Both executables do the same thing, but one is a console program and the other is windows service. The console program is intended for easier debugging in Windows and for installation as a Linux service.
 
One of the shared pas files have code enclosed in an conditional compilation directive like {$ifdef DEF1} ... {$else} ... {$endif} and that DEF1 is defined only in one of the projects.

The thing is that both projects have their default value for 'Unit output directory: lib\$(TargetCPU)-$(TargetOS)' and when one of the projects reloaded into the IDE and then 'Run/Compile' used, then the shared pas file doesn't get rebuilt, despite the different set of defines. The resulting executable gets linked with the old (pre-)compiled unit (from the other project) and that results in an invalid program.

I know, the best thing is to put different unit output directories for each project, but somehow I missed to do that right.   

The next funny thing is that when I use the 'Run' button instead of 'Run/Compile' the IDE somehow manages to compile it right (?!).

Finally, to summarize my questions:
  • How IDE checks the dependencies of the source files during compile? Is only the timestamp involved or there is additional parameters like project name, compiler options, etc.? 
  • Is the 'Run' button behaves differently from 'Run/Compile' option and then 'Run/Run'?
  • Is that a real IDE issue, or I'm starring at it too much? (For me it was real, since I had an embarrassing moments putting non-working service at the target computer)

I have prepared a sample, depending of what is built first and then reloading the other project, then using 'Run/Compile', F9 - either the GUI program gives RunError(103) or the console program doesn't output its message.

Lazarus 1.9.0 r63034 FPC 3.1.1 i386-win32-win32/win64
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

prof7bit

  • Full Member
  • ***
  • Posts: 161
Re: Sharing same source file in two projects
« Reply #1 on: October 03, 2021, 11:20:58 am »
This sounds like a bug to me.

I would expect a build system to always detect when compiler options have changed and rebuild all affected object files.

egsuh

  • Hero Member
  • *****
  • Posts: 1273
Re: Sharing same source file in two projects
« Reply #2 on: October 03, 2021, 11:34:41 am »
What if you first Shift-F9 and then F9?

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Sharing same source file in two projects
« Reply #3 on: October 03, 2021, 11:42:32 am »
I've come across similar issues when conditionals and include files are used in concert (e.g. to switch between static and dynamic linkage of an imported library). The only solution I could find was to use "Clean Directory" which would force a complete build from scratch.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

prof7bit

  • Full Member
  • ***
  • Posts: 161
Re: Sharing same source file in two projects
« Reply #4 on: October 03, 2021, 11:50:16 am »
Try Run|Build instead of Run|Compile.

I honestly don't know what the purpose of Run|Compile is meant to be, just like "build" it invokes the linker, so coming from any other build system on the planet one would naturally expect it to check all prerequisites for linking (and that would make it the same as "build"), but it seems to leave out some important steps in the middle (undocumented?) but then still link the now inconsistent object files and thereby only cause confusion.

If I could I would remove it from the menu entirely. If it can produce incorrect builds it has no reason to exist in the first place.
« Last Edit: October 03, 2021, 12:00:48 pm by prof7bit »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Sharing same source file in two projects
« Reply #5 on: October 03, 2021, 11:58:23 am »
Try Run|Build instead of Run|Compile.

Didn't make any difference in my case.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

prof7bit

  • Full Member
  • ***
  • Posts: 161
Re: Sharing same source file in two projects
« Reply #6 on: October 03, 2021, 12:01:40 pm »
Try Run|Build instead of Run|Compile.
Didn't make any difference in my case.
Then I would clearly consider it a bug.

egsuh

  • Hero Member
  • *****
  • Posts: 1273
Re: Sharing same source file in two projects
« Reply #7 on: October 03, 2021, 12:03:48 pm »
You can change the output directory any time --- now, I guess.

prof7bit

  • Full Member
  • ***
  • Posts: 161
Re: Sharing same source file in two projects
« Reply #8 on: October 03, 2021, 12:06:01 pm »
You can change the output directory any time --- now, I guess.
This treats the symptom, but not the underlying cause.
It is wasting disk space and increasing CO2 production and warming the climate by needlessly compiling all units twice that do not have that ifdef.
« Last Edit: October 03, 2021, 12:11:51 pm by prof7bit »

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: Sharing same source file in two projects
« Reply #9 on: October 03, 2021, 12:16:44 pm »
Cannot confirm the issue with the demo projects using Laz-main/fpc-main, Laz 2.0.8/FPC 3.0.4, Laz 1.8.4/FPC 3.0.4, all 32 bit on Win 10 (64bit). I am compiling with F9; I almost never use "Run/Compile" because it compiles only the current file.

Thought that the define LCL is maybe more important for the IDE than others. So, I replaced the {$IFNDEF LCL} by {$IFNDEF USE_LCL}, and defined "USE_LCL" in the gui project's compiler options ("Custom Options") so that it is valid all over the project. This way I could reproduce the issue for one time, but after a "Build" (Shift F9) it does not appear again whatever I do...

So there must be something else missing to trigger the issue.
« Last Edit: October 03, 2021, 12:35:36 pm by wp »

prof7bit

  • Full Member
  • ***
  • Posts: 161
Re: Sharing same source file in two projects
« Reply #10 on: October 03, 2021, 12:30:52 pm »
I also cannot reproduce this with "Build"

I can reliably reproduce it with "Compile"

which means I will stick to my habit of "shift-F9" because this just works.

BTW: I can also reproduce the problem with "Run" (contrary to what OP described), this means the IDE will use the "compile" command before running, it won't do a proper build!
« Last Edit: October 03, 2021, 12:42:27 pm by prof7bit »

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Sharing same source file in two projects
« Reply #11 on: October 03, 2021, 01:15:11 pm »
Xref to https://forum.lazarus.freepascal.org/index.php/topic,53979.msg400416.html#msg400416 with Sven's observation:

Quote
If you're doing this inside a unit it's a really, really bad idea to do so, because changing the defines won't lead to the units be recompiled thus you might include a unit compiled with LIBRARY in a program instead of a library.

Also https://forum.lazarus.freepascal.org/index.php/topic,53028.msg391737.html#msg391737 and https://forum.lazarus.freepascal.org/index.php/topic,52884.msg390797.html#msg390797

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Sharing same source file in two projects
« Reply #12 on: October 04, 2021, 12:40:56 pm »
Thanks all for your replies!

As I wrote in my 1-st post - There is nobody to blame for this but me. I usually separate the intermediate directories for each project/build mode for that very reason.

@Mark,
Thank you for pointing me on Sven's post on that. His opinions are pretty undeniable rules, tho.

But I'm still curious. My understanding on Compile|Build commands are that the Build command must unconditionally compile all units, while the Compile must check each unit dependencies and then compile only those that have been changed.

And there is the question of the dependencies checking. Obviously the dependency tree expands on the units used into the 'uses' clauses. Also, files from the {$I file.inc} clauses must be included. And then, it comes the tricky issue of:
Code: Pascal  [Select][+][-]
  1. {$IFDEF DEF1}
  2. {$I file1.pas}
  3. {$ELSE}
  4. {$I file2.pas}
  5. {$ENDIF}
  6.  
   
in which the dependency itself depends on the DEF1.

In gcc there is a workaround for this, a dependency file (*.d) can be generated with the help of -MM option, which dependency file will contain the includes according to all other options (and additional defines). But the pre-processor is a separate entity in gcc, not sure how this is implemented in fpc.

"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Sharing same source file in two projects
« Reply #13 on: October 04, 2021, 02:13:56 pm »
As I wrote in my 1-st post - There is nobody to blame for this but me. I usually separate the intermediate directories for each project/build mode for that very reason.

In my case I had: separate directories for the Python2 and Python3 interfaces, and consistent naming within each directory. And if anything it made matters worse.

Quote
pre-processor is a separate entity in gcc, not sure how this is implemented in fpc.

FPC has no preprocessor and no facility for invoking one. And I'd throw in in passing that there are some things e.g. the % sigil in comments which are recognised and actioned by multiple members of the ecosystem.

I agree that the situation is uncomfortable, and I'd also comment that things like the IDE highlighter etc.- to which people seem prepared to give unstinting adulation- have absolutely no problem with defines: why then does compile/build?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Sharing same source file in two projects
« Reply #14 on: October 04, 2021, 03:05:51 pm »
But I'm still curious. My understanding on Compile|Build commands are that the Build command must unconditionally compile all units, while the Compile must check each unit dependencies and then compile only those that have been changed.

Correct. And defines are mostly ignored, so need a build to force. If rebuild didn't work, something fishy is going on (usually duplicate files and/or differing include/unit/object directories in the project)

Quote
And there is the question of the dependencies checking. Obviously the dependency tree expands on the units used into the 'uses' clauses. Also, files from the {$I file.inc} clauses must be included. And then, it comes the tricky issue

Such .inc dependencies and their datetime are stored in the precompiled unit files (*.ppu). So when a .ppu is loaded, the .inc file can be checked. This is also why it is a bad idea to have inc files with the same name.

Quote
in which the dependency itself depends on the DEF1.

Ignored.

Quote
In gcc there is a workaround for this, a dependency file (*.d) can be generated with the help of -MM option, which dependency file will contain the includes according to all other options (and additional defines). But the pre-processor is a separate entity in gcc, not sure how this is implemented in fpc.

FPC builds faster than most C++ compilers, so microoptimizing this is often not worthwhile. Just do a build instead of an incremental if you change compiler parameters (defines, but also e.g. release <-> debug build mode)

In general, the build system of Borland origin pascals (TP,FPC,Delphi probably VP too ) is hard to compare with the way that C++ builds. In C++ the compiler is pretty stupid, and all intelligence is in tools and its info in separate files.
« Last Edit: October 04, 2021, 03:10:05 pm by marcov »

 

TinyPortal © 2005-2018