View Issue Details

IDProjectCategoryView StatusLast Update
0020652FPCCompilerpublic2015-11-22 14:20
ReporterAnton Kavalenka Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Platformall 
Product Version2.7.1 
Summary0020652: Compiler: Resource linking ($R) directive has opposite order to Delphi
DescriptionThis a little-bit annoying:

{$ifdef FPC}
{$R 'a.rc' 'a.res'}
{$else}
{$R 'a.res' 'a.rc'}
{$endif}
Steps To Reproducecompile and test attached project.
try to remove {$IFDEF FPC}
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget
Attached Files

Activities

2011-11-08 17:01

 

a.zip (63,142 bytes)

Anton Kavalenka

2011-11-08 17:56

reporter   ~0053936

I meant $R has opposite parameters order

Paul Ishenin

2011-11-09 03:42

developer   ~0053944

interesting why to use {$R 'a.rc' 'a.res'} at all instead of single {$R 'a.rc'}

Anton Kavalenka

2011-11-09 12:40

reporter   ~0053953

To make code compilable both in FPC and Delphi.
Unfortunately Delphi does not understand {$R 'a.rc'}

Error: RLINK32: Error reading file "P:\fpctest\fpctest33\a.rc"

It tries to link the first file mentioned in {$R} directive

Anton Kavalenka

2013-01-29 17:37

reporter  

scandir.diff (3,075 bytes)   
Index: scandir.pas
===================================================================
--- scandir.pas	(revision 23533)
+++ scandir.pas	(working copy)
@@ -1032,30 +1032,73 @@
         do_delphiswitch('Y');
       end;
 
+    procedure res_wildcard(var s:string); { used by dir_resource() }
+    begin
+      { replace * with the name of the main source.
+          This should always be defined. }
+      if s[1]='*' then
+      if Assigned(Current_Module) then
+      begin
+        delete(s,1,1);
+        insert(ChangeFileExt(ExtractFileName(current_module.mainsource),''),s,1 );
+      end;
+    end;
+
+    const sRcScript='.rc';
     procedure dir_resource;
       var
-        s : string;
+        s, s1, bs : string;
+        spos: integer;
       begin
         current_scanner.skipspace;
+        { starts with single quote }
         if scanner.c = '''' then
           begin
-            s:= current_scanner.readquotedstring;
-            current_scanner.readcomment
+            s:=current_scanner.readquotedstring;
+            current_scanner.skipspace;
+            if scanner.c = '''' then
+               s1:=current_scanner.readquotedstring
+            else
+               s1:=current_scanner.readcomment;
           end
-        else
+        else { starts with space }
+        begin
           s:= trimspace(current_scanner.readcomment);
+          spos:=pos(' ',s);
+          if spos>0 then
+          begin
+            s1:=copy(s,spos+1,spos);
+            s:=copy(s,1,spos-1);
+          end
+          else
+            s1:='';
+        end;
 
-        { replace * with the name of the main source.
-          This should always be defined. }
-        if s[1]='*' then
-          if Assigned(Current_Module) then
-            begin
-              delete(S,1,1);
-              insert(ChangeFileExt(ExtractFileName(current_module.mainsource),''),S,1 );
-            end;
-        s:=FixFileName(s);
-        if ExtractFileExt(s)='' then
-          s:=ChangeFileExt(s,target_info.resext);
+        if s<>'' then { 1st directive param - force to target resource name }
+        begin
+           res_wildcard(s);
+           s:=FixFileName(s);
+           if ExtractFileExt(s)='' then
+             s:=ChangeFileExt(s,target_info.resext);
+        end;
+
+        if s1<>'' then { 2nd directive param - assume .rc script }
+        begin
+           res_wildcard(s1);
+           s1:=FixFileName(s1);
+           if ExtractFileExt(s1)='' then
+             s1:=ChangeFileExt(s,sRcScript);
+        end;
+        { normalize order: s - script name, s1 - binary name }
+        if (ExtractFileExt(s)=target_info.resext) and (ExtractFileExt(s1)=sRcScript) then
+        begin
+          bs:=s; s:=s1; s1:=bs; { R res rc, s becomes .rc}
+        end else
+        if (ExtractFileExt(s1)=target_info.resext) and (ExtractFileExt(s)=sRcScript) then
+        begin
+          { R rc res, s stays .rc}
+        end;
+
         if target_info.res<>res_none then
           begin
           current_module.flags:=current_module.flags or uf_has_resourcefiles;
scandir.diff (3,075 bytes)   

Anton Kavalenka

2013-01-29 17:38

reporter   ~0065284

Patch provided upon current trunk.

IMO there is no way to pass separate resource script name and binary output name to resource compiler.

Thaddy de Koning

2013-01-30 20:57

reporter   ~0065328

Last edited: 2013-01-30 21:15

View 8 revisions

Delphi doesn't need the x.res to be physically present as a file if you add the x.rc.
Although it needs (requires) the syntax to be 'x.res' 'x.rc'.
In Delphi speak it means the linker instruction: "build the binary resource from the given resource script".

The x.res doesn't even have to exist.
The linker calls the resource compiler on x.rc to create x.res before linking it.
 
Hence left to right x.res from x.rc.

Delphi never properly documented this behaviour. I did explain this on nldelphi.com a couple of years ago (and even way back in 'UNDU' in 1997) and even then it was not immediately clear to everybody.

Also note that this only works in Delphi on full builds, not on a compile or recompile: Delphi's internal linker calls the external brcc32 executable here. And has done so since Delphi 2.

If there is a x.res already present, the linker won't call out to brcc32 on a simple compile, hence the full build.

Thaddy de Koning

2013-01-30 21:31

reporter   ~0065329

Last edited: 2013-01-31 06:35

View 4 revisions

So the way to do it is ignore x.rc if x.res exists unless -B is specified as a compiler option. In that case and only that case x.rc should be evaluated and the resource script be compiled.

[EDIT]
This is really a Lazarus, maybe also an fpmake, issue:
The compiler should simply accept the syntax, but the IDE should resolve it in its build script and call out to the resource compiler.
Further more:
- In Delphi this syntax only works if the x.rc file is explicitly added to the project.
- In Delphi it only works properly on full builds/rebuilds
- In Delphi 'x' cannot be a '*' which is a special case for the project name.

Sven Barth

2013-01-31 07:55

manager   ~0065334

I don't think that FPC should ignore the syntax. Not everyone uses Lazarus. Also FPC supports the syntax with the opposite order, so I don't see why it should ignore the Delphi variant (if we decide to support it).

Regards,
Sven

Thaddy de Koning

2013-01-31 12:48

reporter   ~0065341

Last edited: 2013-01-31 13:00

View 3 revisions

For good measure, Sven, I made the remark about fpmake. I don't think the support of a similar syntax was fully understood when it was implemented and the implementation of - then - Borland was and still is not flawless. Un-documenting by obscurity, maybe? :)
I think this needs more research before anything further than reversing for all platforms the current syntax to the Delphi syntax and make it a do nothing. This is not an easy fix.

Sven Barth

2013-01-31 14:07

manager   ~0065344

I've taken a closer look at the compiler's scanner and we might be able to solve this without problems.

The current situation is that FPC does not handle the second part at all. Unlike what Anton reported FPC does only read the first name in single quotes and then simply skips to the trailing "}" without looking at any other part at all. The specified file is then added to the list of resources for that unit.
Then later it checks all the resources whether they
a) exist at all
b) whether it is a compiled resource (e.g. *.res) or not (e.g. *.rc) and compiles it in the latter case

With this knowledge there is nothing really stopping us from implementing Delphi's syntax. If we encounter a second quoted string then we handle the whole directive as "res" & "rc" instead of "res" | "rc". We also need to extend some structures a bit, so that we can pass the second filename along, but that shouldn't be too much of a problem.

Regards,
Sven

Thaddy de Koning

2013-01-31 16:41

reporter   ~0065353

Last edited: 2013-01-31 16:46

View 3 revisions

As long as you keep in mind only to accept this syntax on full builds, you may be right. res AND rc should only lead to a resource recompile if rc changed or res is not there or -B is specified.

Tnx for investigating. This particular syntax has obviously fascinated me for years and, though it is a nice feature, is never fully completely implemented in Delphi and led to lot's of "duplicate resources" or "Missing resource" error messages and support questions.
Btw: my explanation is by what I recall from a discussion with Danny Thorpe at the Borland campus in the '90's. He also said that it was - not ad verbatum but close - "one of these things we need internally, but is not finished (may be polished, one of these two)". I have never seen any change in that situation ;) If you check out the Delphi help on {$R you will understand what I mean. Especially what is *not* there. But it was never mend to be a side effect. It was an intentional syntax.

Issue History

Date Modified Username Field Change
2011-11-08 17:01 Anton Kavalenka New Issue
2011-11-08 17:01 Anton Kavalenka File Added: a.zip
2011-11-08 17:56 Anton Kavalenka Note Added: 0053936
2011-11-09 03:42 Paul Ishenin Note Added: 0053944
2011-11-09 12:40 Anton Kavalenka Note Added: 0053953
2013-01-29 17:37 Anton Kavalenka File Added: scandir.diff
2013-01-29 17:38 Anton Kavalenka Note Added: 0065284
2013-01-30 20:57 Thaddy de Koning Note Added: 0065328
2013-01-30 21:01 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:02 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:05 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:09 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:11 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:12 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:15 Thaddy de Koning Note Edited: 0065328 View Revisions
2013-01-30 21:31 Thaddy de Koning Note Added: 0065329
2013-01-30 21:37 Thaddy de Koning Note Edited: 0065329 View Revisions
2013-01-31 05:44 Thaddy de Koning Note Edited: 0065329 View Revisions
2013-01-31 06:35 Thaddy de Koning Note Edited: 0065329 View Revisions
2013-01-31 07:55 Sven Barth Note Added: 0065334
2013-01-31 12:48 Thaddy de Koning Note Added: 0065341
2013-01-31 12:54 Thaddy de Koning Note Edited: 0065341 View Revisions
2013-01-31 13:00 Thaddy de Koning Note Edited: 0065341 View Revisions
2013-01-31 14:07 Sven Barth Note Added: 0065344
2013-01-31 16:41 Thaddy de Koning Note Added: 0065353
2013-01-31 16:44 Thaddy de Koning Note Edited: 0065353 View Revisions
2013-01-31 16:46 Thaddy de Koning Note Edited: 0065353 View Revisions