Makefile : using environment variable or cmd line argument - build

I have a requirement where i need to set a variable in the makefile depending upon :
If it is passed as an argument to the makefile
If it is set as an environment variable.
The name of the variable is same if set as env variable or passed as argument.
Priority is the one passed as argument.

Make already provides this behavior, built in. When make starts all environment variables are imported as make variables. And any variable assignment set on the command line overrides all other settings of the variable, including both in the environment and in the makefile.
Can you be more clear about what you want, that is not the same as the default behavior?

Related

Setting environment variable from within library C++

So basically I am trying to set an environment variable in my C++ code to force the number of threads to be 1. I am using multiple machine learning libraries which by default use OpenMP and can be forced to operate in single thread mode by setting the following environment variable: OMP_NUM_THREADS=1
Here's my issue. I want to set this environment variable from within a library I am building.
When I set the environment variable from my main function (executable linking against the library I am building) then it works as expected (only 1 thread is used during the execution of the program):
auto implPtr = FRVT_11::Interface::getImplementation();
implPtr->initialize(CONFIG_DIR);
char ompEnv[]="OMP_NUM_THREADS=1";
putenv( ompEnv );
// More code
However, if I try to set the environment variable from within the library I am building (for example from within the getImplementation function), then the number of threads used is 4 instead of 1:
// This does not work
std::shared_ptr<FRVT_11::Interface> FRVT_11::Interface::getImplementation() {
char ompEnv[]="OMP_NUM_THREADS=1";
putenv( ompEnv );
return std::make_shared<MyImplementation>();
}
Any ideas why this would be the case? I am building and shipping the library so I need the number of threads to be set from within the library.
Your "library function" version is undefined behavior.
Your "main function" version is also likely undefined behavior, as an extra bonus, but you aren't aware of it, yet.
From the Linux version of the putenv(3) manual page (other OS implementations are likely the same):
The string pointed to by [the parameter to putenv()] becomes part of
the environment, so altering the string changes the environment.
That's your big, honking, alarm bell: you better not even think of touching this string, ever again, even with a 10-foot pole, because it is now a part of the environment.
In your shared library version:
char ompEnv[]="OMP_NUM_THREADS=1";
This array is a local variable in the function. Therefore, this array gets destroyed when this function returns. But this array is also passed as a parameter to putenv(). Grand total: as soon as this function returns, one of your environment variables is now a dangling pointer.
There is no sufficient information to conclusively prove that your "main function" version is also undefined behavior, but it's highly likely, too.

Clear all Cmake variables at once

Is there any command that I can place in a CMakeLists.txt file to clear all the variables that have been defined?
If I understood well I can selectively clear them doing 'unset' selectively on each variable, but I would need to do something more like 'unset(*)'.
You can unset all variables like this:
get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
unset(${_variableName})
endforeach()
This essentially gets all variables at the global scope and calls unset on them. As #'Some programmer dude' noted, this is not recommended, and will likely cause CMake to stop functioning correctly.

Default for optional string option in .ado program

I wrote a .ado program that generates a new variable. I would like to have a
default suffix appended to the new variable, but allow a user-specified
suffix. That is, by default append _tr to the original variable's name, but
allow a user-specified suffix, say _tr1pct.
Is this possible with syntax?
My syntax line is as follows.
syntax varlist [if] [in] ///
[, Byvar(varlist) Tail(real 1) ///
Suffix(string) noRelabel]
And the suffix is applied later in the program as follows.
clonevar `x'_`suffix' = `x' ///
if `thisuse' & inrange(`pct', `tail', 100 - `tail')
I tried Suffix(string tr) and Suffix(string "tr"), but these are syntax
errors. I guess I can't have a default argument to an option (and I can't find
anything about defaults for string options, in any case).
Is there a way to give local macro suffix a default?
Yes. You can declare Suffix(string) as an option and then after syntax go
if "`suffix'" == "" local suffix "_tr"
If the user didn't specify an argument, the local macro suffix will be empty and you define what it should be. That's a default.
I don't know a reason why syntax does not allow this, but I take this to be the standard procedure given that it does not.

Set system variable from C++

This shell script
#!/bin/csh
set VAR=12345
echo $VAR
will peacefully give the output 12345 at shell.
I need to use C++ to do the same in some part of the code:
string str = "12345";
retValue="set var1= "+str;
system(retValue1.c_str());
system("echo $var1");
This doesn't create a system variable var1 and echos null which is understandable as each system function would create a child process with different environment variables. So I combine them as follows using just one system function...but it echos null again.
retValue="set var1= "+str;
retValue1=retValue+";\n echo $var1";
system(retValue1.c_str());
Can someone please guide me to set up the system variable thru C++.
Thanks a lot in advance!
Look at setenv in <cstdlib>:
#include <cstdlib>
setenv("VAR", "12345", true);
You basically can't do that.
You could call putenv to change environment variables in your own process and in all future children processes, but there is no way (and this is good) to change the environment of the parent shell process.
You could have a use convention for your C++ program that e.g. it is outputting some shell commands to be sourced (or eval-ed) by the user. An example of this is ssh-agent -s.
You can use putenv().
#include <cstdlib>
...
putenv("VAR=12345");
This is very convenient, but the string is not copied by putenv. This means that if you modify it later, then you modify the environment. That's not an issue for a literal, but the way you are forming your strings, using std::string is not readily compatible with putenv().
The alternative then is to use setenv()
#include <cstdlib>
...
setenv("VAR", "12345", true);
With setenv(), copies of the input are made and you are safe to dispose of the strings after calling setenv().
The function you want is probably putenv(). You didn't specify which OS you are on, so I'll assume Linux because that's the man page I have handy:
int putenv(char *string);
The putenv() function adds or changes the value of environment
variables. The argument string is of the form name=value. If name
does not already exist in the environment, then string is added to the
environment. If name does exist, then the value of name in the
environment is changed to value. The string pointed to by string
becomes part of the environment, so altering the string changes the
environment.
IIRC, there is a putenv on win32 as well. Finally you might try looking at this question, possibly a dup
Above answers explains correctly as to how to set environment variable from a C++ program which is basically setenv()
The only other point i wanted to make is that why your approach doesn't work? The reason is, that when a process is loaded, the system command is loaded with new context - an equivalent of a new shell. Actually your environment variable is getting set but when you comeback it is lost.
Refer to this http://pubs.opengroup.org/onlinepubs/007904975/functions/setenv.html.
Infact, the setenv() sets the env variables of parent process! Which is why it works for you.
Note that the otherwise excellent CPPreference site does not seem to mention setenv among the functions available in the <cstdlib> header, only getenv. This may not be a problem though as I could use setenv by #include-ing <cstdlib> on a Centos 7 system with GCC 9.1. I suspect in most cases <cstdlib> is just a thin wrapper around <stdlib.h>.
Another small thing to note is that setenv takes C-style character arguments (also for the value of the environment variable to be set). If you use C++ strings (as you should), don't forget to convert them using their .c_str() method.

How do I find the 'temp' directory in Linux?

How do I find the 'temp' directory in Linux? I am writing a platform neutral C++ function that returns the temp directory. In Mac and Windows, there is an API that returns these results. In Linux, I'm stumped.
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Check following variables:
The environment variable TMPDIR
The value of the P_tmpdir macro
If all fails try to use the directory /tmp.
You can also use tempnam function to generate a unique temporary file name.
Edit: Fair point from the commenter. tmpnam isn't a good choice these days; use mktemp/mkstemp instead.
Historical answer: Be POSIX compliant, and use tmpnam (which will give you a full filename in a temporary location).
Use the value of the $TMPDIR environment variable, and if that doesn't exist, use /tmp.
The accepted sequence, specifically from a GNU standpoint, is:
Check the environmental variable TMPDIR (getenv("TMPDIR")) only if
the program is not running as SUID/SGID (issetugid() == 0)
Otherwise use P_tmpdir if it is defined and is valid
and finally, should those fail, use _PATH_TMP available from paths.h
If you are adding an extension or module, check to see if the core provides a function for this purpose. For example, PHP exports php_get_temporary_directory() from main/php_open_temporary_file.h.
In standard c, you could try: P_tmpdir