www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Forcing my module to be initialized first

reply dan <dan.hitt gmail.com> writes:
I have some code that i would like executed before anything else 
is.

The code is to set an environment variable which is used by a 
library.  I'm trying to find some way to avoid setting the 
environment variable on the command line, or in any shell script 
or initialization file.

I think the place to put such code would be in a 'static this' 
inside a module.

So i need some way to force my module to be initialized first, 
ahead of all others.

I suppose if i could figure out a way to make all other modules 
depend on my module this would happen, but the module which uses 
the variable i want to set is in some already-compiled dynamic 
library that i would prefer not to touch.

Alternatively, is there some entry point besides main that i 
could use, that executes before main and before any module 
initialization is done? (Is it possible to get in before the d 
runtime starts?)  Although i would prefer to code in d, it would 
be ok to do it in c.

This is on MacOS (Catalina) in case that makes a difference, and 
i'm using dmd v2.104.0.

Thanks in advance for any clues.

dan
Oct 15 2023
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 16/10/2023 4:31 PM, dan wrote:
 I suppose if i could figure out a way to make all other modules depend 
 on my module this would happen, but the module which uses the variable i 
 want to set is in some already-compiled dynamic library that i would 
 prefer not to touch.
If its in a shared library, then that shared library gets setup prior to your binary. There is nothing that you can do. You gotta override rather than initialize.
Oct 15 2023
parent reply dan <dan.hitt gmail.com> writes:
On Monday, 16 October 2023 at 03:33:55 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 On 16/10/2023 4:31 PM, dan wrote:
 I suppose if i could figure out a way to make all other 
 modules depend on my module this would happen, but the module 
 which uses the variable i want to set is in some 
 already-compiled dynamic library that i would prefer not to 
 touch.
If its in a shared library, then that shared library gets setup prior to your binary. There is nothing that you can do. You gotta override rather than initialize.
Thanks Rikki. I was wrong in my statement of the problem: it is not a dynamic library, but rather a static library, libgtkd-3.a. I apologize for being so careless. libgtkd-3.a throws an exception before main is reached, in the Loader.d file, in a method with signature 'public static void loadLibrary(string library)'. That method is used trying to load a library which really is dynamic, libatk-1.0.0.dylib. That library is in my system, among the Mac ports files, in a standard place, namely /opt/local/lib. I can set the environment variable GTK_BASEPATH to help it out, and that works, but i would like to do all of this inside the executable rather than outside the executable. The Loader.d file depends on std.process. So, given that i was wrong and it is not a dynamic library i'm trying to get in ahead of, but a static one, is there a way to execute a small snippet of code after std.process is initialized, but before any other code (such as Loader.d) uses it? Thanks in advance for any ideas. dan
Oct 15 2023
parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
Okay, after looking at gtkd, I don't think this can be solved with 
module constructors or swapping out to lazy initialization.

One way that might work however is to use a crt_constructor as that runs 
before the D stuff. However it would now hard code your program to your 
system. Over all my suspicion is that there is something wrong with your 
system related to library lookup paths and that should be fixed instead.

```d
void main() {
     import std.stdio;
     import std.process;
     writeln(environment["GTK_BASEPATH"]);
}

pragma(crt_constructor) extern(C) void myEnvironmentVarSetter() {
     import core.sys.posix.stdlib : putenv;
     putenv(cast(char*)"GTK_BASEPATH=~/bin/gtk".ptr);
}
```
Oct 16 2023
parent reply dan <dan.hitt gmail.com> writes:
On Monday, 16 October 2023 at 10:23:54 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 Okay, after looking at gtkd, I don't think this can be solved 
 with module constructors or swapping out to lazy initialization.

 One way that might work however is to use a crt_constructor as 
 that runs before the D stuff. However it would now hard code 
 your program to your system. Over all my suspicion is that 
 there is something wrong with your system related to library 
 lookup paths and that should be fixed instead.

 ```d
 void main() {
     import std.stdio;
     import std.process;
     writeln(environment["GTK_BASEPATH"]);
 }

 pragma(crt_constructor) extern(C) void myEnvironmentVarSetter() 
 {
     import core.sys.posix.stdlib : putenv;
     putenv(cast(char*)"GTK_BASEPATH=~/bin/gtk".ptr);
 }
 ```
Really awesome, Rikki, your code does the trick. Thank you so much for your pragma. Since you are so right about the code, maybe you are also right about my system. For reference, i'll describe it in case anybody else somehow wanders into the same situation. My system is a Mac Catalina (OSX 10.15). I installed the latest dmd i could find, directly from the Digital Mars website. This was so that i could use any ports system (macports, fink, or brew) and keep the same d compiler. The dmd compiler is in /usr/local/bin/dmd, and the files are in some standard location /Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/..... I installed the gtk stuff (but not gtkd) from macports, and that all went into /opt/local, which is where macports puts things. I believe that gtkd does not have a 'configure' script, so i directly edited the top level GNUMakefile in one spot, to specify a prefix; my changed line was prefix?=/opt/some-particular-path-distinct-from-local-and-all-others I wanted the installation of gtkd to be in some parallel location so that there could be multiple versions if needed, or it could be removed if needed without any chance of disturbing macports or anything else. It built ok, and the demo worked ok (setting GTK_BASEPATH of course, per gtkd's README.md). Note that i built it on an account for which the PATH has /opt/local/bin and /opt/local/sbin at the start. So when gtkd was under construction, it knew just where to find all the gtk files. Thanks again for pointing out the crt_constructor pragma. (Now, i still think that when module initialization order is not forced, it should be something a programmer or systems integrator can choose, but i don't want to be too greedy.) Thanks again for your help!! dan
Oct 16 2023
parent reply bachmeier <no spam.net> writes:
On Monday, 16 October 2023 at 18:28:52 UTC, dan wrote:

 (Now, i still think that when module initialization order is 
 not forced, it should be something a programmer or systems 
 integrator can choose, but i don't want to be too greedy.)

 Thanks again for your help!!

 dan
I changed the subject line, so if case Mike Wey sees this, he knows it's about gtkd. If you haven't already, you make want to post your question at https://forum.gtkd.org/groups/GtkD/
Oct 16 2023
parent dan <dan.hitt gmail.com> writes:
On Monday, 16 October 2023 at 18:57:45 UTC, bachmeier wrote:
 On Monday, 16 October 2023 at 18:28:52 UTC, dan wrote:

 (Now, i still think that when module initialization order is 
 not forced, it should be something a programmer or systems 
 integrator can choose, but i don't want to be too greedy.)

 Thanks again for your help!!

 dan
I changed the subject line, so if case Mike Wey sees this, he knows it's about gtkd. If you haven't already, you make want to post your question at https://forum.gtkd.org/groups/GtkD/
Thanks Bachmeier. It's not exactly a question anymore since Rikki clued me in on the crt_constructor pragma. But i guess i should ask the gtkd forum if there's a better approach, or perhaps a way to set a hook into gtkd for pre-initialization activity (giving a program a chance to scout around for libraries or other resources before actually attempting to load anything). dan
Oct 16 2023
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 16 October 2023 at 03:31:13 UTC, dan wrote:
 I have some code that i would like executed before anything 
 else is.

 The code is to set an environment variable which is used by a 
 library.  I'm trying to find some way to avoid setting the 
 environment variable on the command line, or in any shell 
 script or initialization file.

 I think the place to put such code would be in a 'static this' 
 inside a module.

 So i need some way to force my module to be initialized first, 
 ahead of all others.
You may find this article enlightening: https://devblogs.microsoft.com/oldnewthing/20050607-00/?p=35413
Oct 15 2023
parent dan <dan.hitt gmail.com> writes:
On Monday, 16 October 2023 at 04:26:32 UTC, Paul Backus wrote:
 On Monday, 16 October 2023 at 03:31:13 UTC, dan wrote:
 I have some code that i would like executed before anything 
 else is.

 The code is to set an environment variable which is used by a 
 library.  I'm trying to find some way to avoid setting the 
 environment variable on the command line, or in any shell 
 script or initialization file.

 I think the place to put such code would be in a 'static this' 
 inside a module.

 So i need some way to force my module to be initialized first, 
 ahead of all others.
You may find this article enlightening: https://devblogs.microsoft.com/oldnewthing/20050607-00/?p=35413
Hi Paul, Thanks for the link. It was funny, and for sure too many cooks spoil the broth. I don't think that applies here, since i'm just trying to tweak the initialization order, and i'm the only programmer involved. Of course, i guess all sinners try to justify their wrongdoing --- hope i'm not doing that here!! Thanks for your reply. :) dan
Oct 15 2023