www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Error: getenv cannot be interpreted at compile time

reply "Paul" <paul example.com> writes:
I'd like to create a Terminal using terminal.d and make it 
available across several source files (as a global rather than 
having to pass it around) but when I define it like this in 
global scope:

Terminal Screen = Terminal(ConsoleOutputType.cellular);

I get this error:

Error: getenv cannot be interpreted at compile time, because it 
has no available source code

I don't understand the error and Google doesn't help - can it be 
fixed or am I just using the wrong approach?

TIA

Paul
Feb 17 2015
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 17 February 2015 at 19:17:42 UTC, Paul wrote:
 I don't understand the error and Google doesn't help - can it 
 be fixed or am I just using the wrong approach?
Trying to create it as a global tries to make it as a static variable which means it constructs at compile time. It can't access the TERM environment variable at compile time and that causes the error. Putting Terminal at global scope isn't really ideal, there'd be potential destructor problems (the terminal needs to be cleaned up at program termination). You could stick a pointer to it up there though: Terminal* terminal; // maybe make it shared too but i'd try to avoid that, terminal isn't quite thread safe void main() { auto main_terminal = Terminal(options...); terminal = &main_terminal; scope(exit) terminal = null; // clean up the pointer too when it goes invalid // the rest of your program goes normally // and other functions can use the global pointer } Just make sure you set it in main before doing anything else so the pointer isn't null and you should be good to go. Then when main returns, it will clean up.
Feb 17 2015
parent reply "Paul" <paul example.com> writes:
On Tuesday, 17 February 2015 at 19:29:52 UTC, Adam D. Ruppe wrote:
 On Tuesday, 17 February 2015 at 19:17:42 UTC, Paul wrote:
 I don't understand the error and Google doesn't help - can it 
 be fixed or am I just using the wrong approach?
Trying to create it as a global tries to make it as a static variable which means it constructs at compile time. It can't access the TERM environment variable at compile time and that causes the error. Putting Terminal at global scope isn't really ideal, there'd be potential destructor problems (the terminal needs to be cleaned up at program termination). You could stick a pointer to it up there though: Terminal* terminal; // maybe make it shared too but i'd try to avoid that, terminal isn't quite thread safe void main() { auto main_terminal = Terminal(options...); terminal = &main_terminal; scope(exit) terminal = null; // clean up the pointer too when it goes invalid // the rest of your program goes normally // and other functions can use the global pointer } Just make sure you set it in main before doing anything else so the pointer isn't null and you should be good to go. Then when main returns, it will clean up.
I see, thanks once again :D I don't know why the environment variable isn't accessible at compilation (from a terminal) but that's OS business I guess rather than D related. I did try something similar to your solution but not using a pointer - I'd prefer to avoid using pointers if at all possible!
Feb 17 2015
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Tue, 17 Feb 2015 19:56:19 +0000, Paul wrote:

 I see, thanks once again :D I don't know why the environment variable
 isn't accessible at compilation (from a terminal)
'cause you can't execute C code in CTFE.=
Feb 17 2015
prev sibling parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Tue, Feb 17, 2015 at 07:56:19PM +0000, Paul via Digitalmars-d-learn wrote:
[...]
 I see, thanks once again :D I don't know why the environment variable isn't
 accessible at compilation (from a terminal) but that's OS business I guess
 rather than D related.
Even if you *could* access it at compile time, you don't necessarily want to -- for example, if you distribute your program to other users, they would be stuck with the terminal settings you had while compiling, rather than adapting to *their* environment at runtime. If your terminal doesn't match theirs, it would screw up big time. :-) T -- Shin: (n.) A device for finding furniture in the dark.
Feb 17 2015
prev sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Tue, Feb 17, 2015 at 07:17:41PM +0000, Paul via Digitalmars-d-learn wrote:
 I'd like to create a Terminal using terminal.d and make it available
 across several source files (as a global rather than having to pass it
 around) but when I define it like this in global scope:
 
 Terminal Screen = Terminal(ConsoleOutputType.cellular);
 
 I get this error:
 
 Error: getenv cannot be interpreted at compile time, because it has no
 available source code
 
 I don't understand the error and Google doesn't help - can it be fixed
 or am I just using the wrong approach?
[...] The problem is that the Terminal constructor reads runtime information from the OS, so it cannot be run at compile-time. What you need to do is to initialize it at runtime inside a static this() block: Terminal* screen; static this() { *screen = Terminal(ConsoleOutputType.cellular); } Note that you have to use a pointer, because the Terminal struct does not allow default construction of a Terminal. However, this isn't the end of the story... because the Terminal destructor also resets the terminal back to its original state -- otherwise after the program exits, you'll be stuck in cellular mode, which may not be very nice on some systems where the shell will get very confused (or rather, the user will see gibberish and not understand what's going on). So the *correct* approach is to initialize the Terminal struct in main(), so that when main() exits it will clean up properly: Terminal* screen; void main(string[] args) { // Create the Terminal here auto term = Terminal(ConsoleOutputType.cellular); screen = &term; // so that everybody else can see it ... // main program goes here } // Terminal will clean up properly here It's a bit ugly, but it should work. At least, that's what I do in my own programs that use terminal.d. :-) T -- Too many people have open minds but closed eyes.
Feb 17 2015
parent reply "Paul" <paul example.com> writes:
On Tuesday, 17 February 2015 at 19:35:27 UTC, H. S. Teoh wrote:
 On Tue, Feb 17, 2015 at 07:17:41PM +0000, Paul via 
 Digitalmars-d-learn wrote:
 I'd like to create a Terminal using terminal.d and make it 
 available
 across several source files (as a global rather than having to 
 pass it
 around) but when I define it like this in global scope:
 
 Terminal Screen = Terminal(ConsoleOutputType.cellular);
 
 I get this error:
 
 Error: getenv cannot be interpreted at compile time, because 
 it has no
 available source code
 
 I don't understand the error and Google doesn't help - can it 
 be fixed
 or am I just using the wrong approach?
[...] The problem is that the Terminal constructor reads runtime information from the OS, so it cannot be run at compile-time. What you need to do is to initialize it at runtime inside a static this() block: Terminal* screen; static this() { *screen = Terminal(ConsoleOutputType.cellular); } Note that you have to use a pointer, because the Terminal struct does not allow default construction of a Terminal. However, this isn't the end of the story... because the Terminal destructor also resets the terminal back to its original state -- otherwise after the program exits, you'll be stuck in cellular mode, which may not be very nice on some systems where the shell will get very confused (or rather, the user will see gibberish and not understand what's going on). So the *correct* approach is to initialize the Terminal struct in main(), so that when main() exits it will clean up properly: Terminal* screen; void main(string[] args) { // Create the Terminal here auto term = Terminal(ConsoleOutputType.cellular); screen = &term; // so that everybody else can see it ... // main program goes here } // Terminal will clean up properly here It's a bit ugly, but it should work. At least, that's what I do in my own programs that use terminal.d. :-) T
Got it, I thought it might be something like this but when I tried to do: Terminal screen; ...and initialise it later it failed because of the disabled default constructor. There doesn't seem to be an alternative to using a pointer as it's rather a large struct to pass to functions as is! which was falling
Feb 17 2015
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Tuesday, 17 February 2015 at 20:06:15 UTC, Paul wrote:
 There doesn't seem to be an alternative to using a pointer as 
 it's rather a large struct to pass to functions as is!
yeah, copying is disabled too. The struct isn't big in memory terms (it has few actual data members) but since the destructor does a bunch of things, you wouldn't want it being called often, so a pointer to one made in main is the way to go.
Feb 17 2015