FILE Declaration in Include file in multiple CLASS causes Duplicate Symbol Errors

Older novice again.
My second Class works well in my test, hand-coded app. It does a number of calculations with a group of items related to labels chosen from a list.

A read-only file (.TPS) is loaded into a Cueue for the List. The chosen item is deep-assigned to a Group and the Group passed by reference to the Class.

To use this in other apps, I had hoped to place the overhead declarations in the Include file (above the Class declaration.) This works if I move the Queue and the Group declarations to the Include file but fails when I move the File declaration: Duplicate symbol and naming both Classes’ .obj files and lines from the App’s MAP.

Any help or explanation for this will be greatly appreciated.

I think you need a ,ONCE on your include

I had thought of that. I have ONCE on the include statement in the test app and with the include statement in the Class .clw file.

Perhaps it would be useful to review how ABC classes are constructed? Check out the AB*.inc files in Clarion\libsrc\win. They typically use an OMIT() and an EQUATE.

Are you using this file outside of the class? Or only via methods?
If only via methods then you might try moving the file to the CLW vs the INC
Is this file also declared in the program (unrelated to the class)?

The file is for the program and is declared outside of the Class. It will be needed in any program to load the queue for the list structure in a program that uses the class.

To help elucidate, the class calculates present position of a star based on J2000 data for that star. The file is a list of stars and their data. Individual stars are chosen from the list for calculation by the class. The file and list will enlarge as I add data for more stars. This is intended to be used in a celestial navigation program.
Yes, that is a little passe’ in the GPS age, but I am retired and doing this as a hobby. I hope I am not bothering you professional guys too much. I am appreciative.

I have run into this issue with a FILE in an INC file included by multiple CLASS CLWs showing Duplicate Symbol errors. Jeff ran into with a Class Module QUEUE also and reported it in PTSS. These should be encapsulated by the Class and Private, but they are Not.

I have no simple fix. An easy thing to do is copy the INC file and give the File a unique Label and Prefix. You could have 1 common INC file with all the Fields. The “Unique” INC would need the FILE line and KEYs. Unfortunately the KEY( field ) declarations must have the Prefix i.e. KEY( Pre:field ). Wish the PRE was not required on KEY fields.

There were too many Files and Classes to do my “easy thing” above. What I did was made a separate Project and compiled each Class into an separate DLL. That works but did create 25 Projects and DLLs.


Here’s the contents of a Bug report I submitted and the bug demo project. Maybe @Also knows of a way to make a Class File Private.

I attached a project that shows a problem I’ve run into on conversion of C6 to 11.1 .13815, this code worked fine in C6. If 2 classes declare the same FILE the KEYs throw Duplicate Symbol errors. Compile the attached to see these errors:

If you comment out the Keys in Class_File_Def_Courses.INC then you do not get the KEY Dup Errors. Also … there are 2 Key &= Refs in the Class CLW code you’ll need to comment out for a clean compile.

The only workaround I know is to use a Unique file name and PRE().

This is a BIG Limitation if a Clarion Class cannot declare a FILE in the Class Module CLW without worrying about what FILEs are declared in all the other Classes in the Project. The Class Module data is supposed to be Local ?


Class 1 and 2 are identical except for the name. They both Include a File INC

    MEMBER()                  !ClassWithFile1.CLW   Class ONE
    INCLUDE('ClassWithFile1.INC'),ONCE
    !This Class 1 needs to Access this COURSES File. If this is also in another Class there are Duplicates on the KEYs 
    INCLUDE('Class_File_Def_Courses.INC'),ONCE    !<== the FILE in here 

Class 2 is the same except “2” changes to “1”

    MEMBER()                   !ClassWithFile2.CLW   Class TWO
    INCLUDE('ClassWithFile2.INC'),ONCE
    !This Class 2 needs to Access this COURSES File. If this is also in another Class there are Duplicates on the KEYs 
    INCLUDE('Class_File_Def_Courses.INC'),ONCE    !<== the FILE in here

FILE defined in Class_File_Def_Courses.INC

Courses              FILE,DRIVER('TOPSPEED'),PRE(COU2),CREATE,BINDABLE,THREAD                     
KeyNumber                KEY(COU2:Number),NOCASE,OPT,PRIMARY ! Remove PRE: ? Nope!
KeyDescription           KEY(COU2:Description),DUP,NOCASE  
CompleteDescription         MEMO(1000) 
Record                   RECORD,PRE()
Number                      LONG       
Description                 STRING(40) 
                         END
                     END 

Bug Demo Project
BugDupKeys_ClassesWithSameFile.zip (4.6 KB)

Ok, so since the file exists at a global scope you have two choices.

One use a &File inside of the class, where you inject the object from outside of the class into the class. The limitation here is that you just have a generic &file vs the particular file. So you’ll either need to use property syntax to get things like a given Key, or pass those in as well.

Remember I said there were two choices.
The other choice is to replace the member() (what I call an empty member statement) with member(‘your_global_module’) which gives your class access to the global scope.

The problem with a non empty member statement is you tie the class to one named global module. When I need this access for multiple programs I use conditional omit/compiles to set the member statement (sadly an include doesn’t work for this)
(Sadly pragmas are numbers, not strings)

Edit: more choices

  • fill the queue from outside of the class

  • write the general part of the class as a base class, using an empty member statement and use Virtual methods then derive the class in each program with with VIRTUAL methods (better to use the DERIVED attribute vs virtual)

1 Like

Thanks to all for your help and especially your time. I’m relieved to hear that my problem may be a bug and Not due entirely to my ignorance. (Although, I am sure that is involved.) I will explore the several suggestions and let everyone know what works.
Thanks again.

Did you ever say what type of file this is? If it’s just a text file or CSV, perhaps you could use StringTheory or something, vs a Clarion file driver.

He did say TPS file

I changed my test project to use a DOS file in the INC file and that compiled and worked. I would expect ASCII and BASIC to also work.

ClassIncludesDOSfile.zip (4.6 KB)

So it is KEY’s for sure that are a problem and possibly other more complex parts of a FILE declaration. I tested without KEY’s (has Memo + Blob) and it will compile and work. So it seems KEY is the only “Private Leak”?

TestClassFileInc_NoKEYs.zip (4.9 KB)

1 Like

Great information. And I really don’t need a Key as the queue will perform that function.

Changed the file type to *.dat to accommodate STRING, LONG, & REAL, and eliminated keys. All worked with the table declaration in the Include file.

Thanks to all who helped. Special thanks to you, Carl, for the solution. It certainly helps when others have encountered the same problem (and recognize the way to fix it.)

Interesting.

So if this is used in a multi-dll app, how does that work as far as exporting and EXTERNAL?

Thanks.

The linker reports errors for duplicate names if 2 or more records with the same public name are involved into the link process and if the linker can’t treat them as identical. If records with the same public name are binary equal and all other records referenced from them have the CONST class and contents of that referenced records are binary equal, etc. recursively, the linker can treat records with the same public names as identical. The structures generated for file KEYs have a reference to records having DATA class rather than CONST class - this is the record for list of key fields. Therefore, the linker can’t treat records for file KEYs having the same public names as identical.

The answer: use the only instance of FILE declaration without the EXTERNAL attribute,