The fault when compiling for Linux 64-bit is the following:
The order is right when compiling for Linux 32-bit and Windows 32/64-bit.
This following example code should result in:
constructor fired
inside constructor 134 134534956
outside Namespace 134 134534956
Type udt
As Integer a
Declare Constructor
End Type
Constructor udt()
? "constructor fired"
End Constructor
Static Shared As udt t
Sub init() Constructor
t.a = 134
? "inside constructor ";t.a, @t.a
End Sub
? "outside Namespace ";t.a, @t.a
Sleep
But on 64bit Linux/Ubuntu using FBC64 compiler it results in this:
inside constructor 134 6311024
constructor fired
outside Namespace 0 6311024
Can you please check the generated C code for the example given? For example, compile with 'fbc a.bas -R' and post the generated 'a.c' file. I am getting identical C code generated for both fbc-linux64 and fbc-win64 (except for line endings) on both fbc-1.05 and current 1.06 master. I have attached 'lin64-jm.c' for comparison.
The only difference I can see is that the two sleep commands are missing in the windows version.
What looks like a function declaration on Line 22 :
and on line 58:
I doubt that this forms a part of the issue but it is the only difference I can see.
Yeah, I deleted the sleep command and forgot. I compile, run, and log output from example programs many times and I don't need sleep commands to pause the output. I think it fair to say we have identical compiler output.
So, the next step is to determine if it is gcc behaviour, C run-time behaviour, or linker script that is the issue for you.
As far as I can tell within gcc, there's no guarantee that module constructors must be executed after static variable initializers. Really the only guarantee is that the module constructor is executed before your first executable statement (i.e. main()), though you can control to some degree with the priority attribute. Independantly from module constructors, the static globals should be initialized in the order that they are declared.
I tried using a custom linker script to change the .ctors sort order, but I couldn't reproduce the behaviour you are seeing on Ubuntu. (you can see what the default linker script is with 'ld --verbose', there should be line in there that looks like )
The only time I seen this issue is when I was writing the fbcunit test-suite which relies heavily on module constructors and a few globals. The test-suite was failing due to out of order constructors when running on Travis-CI, which I think is Ubuntu Trusty. Because I don't know what system the test suite might run on., and obviously behaviour is different from one system to the next, the only sane thing to do was to change the design of the API so it does not rely on execution order (it still relies heavily on module constructors though).
Check if that can be the same problem for initialization of static simple numeric variables (value initialized at the declaration level).
If that unstable behavior with objects is normal, it should be desirable for such global variables with construction/destruction have their accesses from a module constructor/destructor forbidden by the compiler.
Last edit: fxm (freebasic.net) 2018-09-20
The variable must have a constructor in order for the problem to appear.
Simple (static shared) module level variables are unaffected because there is no constructor order misfire.
As in this code which prints 44.
Initialization of static simple numeric type variables, that will have a value that can be determined at compile time (for example, default zero, constants, pointers to static objects, pointers to functions, etc), are initialized before any code is executed. These values are part of the EXE image and have an initial value when the EXE is loaded in to memory. In otherwords, trivial static globals where no code is needed to initialize, are guaranteed to be initialized and can be reliably used in all code, including global static object constructors and module constructors.
I think the fix for this bug is a documented recommendation to avoid non-trivial static globals that depend on other non-trivial static globals for their initialization.
Even if global access were forbidden, a module constructor could just call some other procedure that accesses the globals. Even if we replaced the current mechanism with one that ensures that the module constructors are called after (or optionally before), the user can still access globals out of order in object constructors.
I attached an example, showing more cases to avoid.
EDIT:
I think we should expect that:
1) module constructors execute in a deterministic order when used with priority attribute.
2) static globals execute in the order that they are declared
Last edit: Jeff Marshall 2018-09-20
Did some research and set-up ubuntu-64bit 14.04 with gcc 4.8.4 to test this problem and I was able to replicate the behaviour shown in the opening report.
The behaviour appears correct for our current implementation.
Explanation:
Current implementation:
The reason for difference in behaviour:
Updated wiki pages to add information on execution order:
CONSTRUCTOR (Module)
DESTRUCTOR (Module)
The module constructors/destructors expose a low-level feature of the linker and run time environment and execution order can vary across platforms.