Optional Environment Arguments to SCons Builders - environment-variables

I've noticed that calls to Object and Library builders sometimes take optional arguments at the end such as
Object('hello.c', CCFLAGS='-DHELLO')
Object('goodbye.c', CCFLAGS='-DGOODBYE')
Can Object, Library and SharedLibrary all take an arbitrary set of them or are they limited to a specific set of variables? If so this should save our current very large SCons build at work some time I hope.

The C/C++ builders recognize a specific set of arguments, called Construction Variables.
These variables can either be set on the environment or when calling the builder as you do in your question. Its often easier to set them on the environment, thus making the calls to the builders simpler, and then only modify the variables when necessary.
Here is an example:
env = Environment()
# Notice that CPPPATH, CPPDEFINES, LIBS, and LIBPATH dont include the
# compiler flags -I, -D, -l, and -L respectively, SCons will add those
# in a platform independent manner
env.Append(CCFLAGS=['-g', '-O2'])
env.Append(CPPPATH=['some/include/path'])
env.Append(CPPDEFINES=['YOUR_DEFINE'])
env.Append(LIBS=['pthread'])
env.Append(LIBPATH=['some/lib/path'])
# All of these builder calls use the construction
# variables set on the environment above
env.Object('hello.c')
env.Object('goodbye.c')
env.Program('main.cc')
If you want to override a specific variable, you can do the following
env.Object('hello.c', CPPDEFINES='HELLO')
Or, if you want to append to a specific variable, with just one call, you can do the following:
env.Object('hello.c', CPPDEFINES=[env['CPPDEFINES'], 'HELLO'])

What Brady said is mostly correct.
However, you can append any (number of) Environment() variables to the end of any builder. These create an OverrideEnvironment() which is then what is used to run the builder.
If you were to change the value of CCCOM and/or any variable which feeds into the command line for running the compiler then adding those variables to builder call would also have some impact.
If you specify a variable which has no impact on the current builder or even one which is not defined anywhere in SCons or any builders you may have created SCons will not issue a warning or an error.

Related

Detect environment variable change in Tcl

Is there any way to detect an environment variable change DURING the execution of a Tcl script (I use Tk so the execution can be long) ?
For instance, if I define an environment variable MYVAR=1, then I can access it from Tcl by writing $ENV(MYVAR). Let's say now that during the execution of the Tcl program, I switch MYVAR to 2. Is there a way, or maybe a command, that scans every environment variable again so I can get 2 when I call $ENV(MYVAR) ?
First off, other processes will not see changes to the environment variables of any process. Children get a copy of the current environment when they are created, and that's it.
Secondly, to see a change in the environment variables, put a trace on the ::env variable (but tracing an individual variable is not recommended). I can't remember if this works reliably between threads, but within a thread it's pretty good provided you don't have C code modifying the variables behind your back.
proc detectChange {name1 name2 op} {
# We know what name1 and op are in this case; I'll ignore them
if {$name2 eq "MYVAR"} {
puts "MYVAR changed to $::env(MYVAR)"
}
}
trace add variable ::env write detectChange
Note that Tk internally uses traces a lot (but the C API for them, not the Tcl language API for them).

How to pass an array from Bazel cli to rules?

Let's say I have a rule like this.
foo(
name = "helloworld",
myarray = [
":bar",
"//path/to:qux",
],
)
In this case, myarray is static.
However, I want it to be given by cli, like
bazel run //:helloworld --myarray=":bar,//path/to:qux,:baz,:another"
How is this possible?
Thanks
To get exactly what you're asking for, Bazel would need to support LABEL_LIST in Starlark-defined command line flags, which are documented here:
https://docs.bazel.build/versions/2.1.0/skylark/lib/config.html
and here: https://docs.bazel.build/versions/2.1.0/skylark/config.html
Unfortunately that's not implemented at the moment.
If you don't actually need a list of labels (i.e., to create dependencies between targets), then maybe STRING_LIST will work for you.
If you do need a list of labels, and the different possible values are known, then you can use --define, config_setting(), and select():
https://docs.bazel.build/versions/2.1.0/configurable-attributes.html
The question is, what are you really after. Passing variable, array into the bazel build/run isn't really possible, well not as such and not (mostly) without (very likely unwanted) side effects. Aren't you perhaps really just looking into passing arguments directly to what is being run by the run? I.e. pass it to the executable itself, not bazel?
There are few ways you could sneak stuff in (you'd also in most cases need to come up with a syntax to pass data on CLI and unpack the array in a rule), but many come with relatively substantial price.
You can define your array in a bzl file and load it from where the rule uses it. You can then dump the bzl content rewriting your build/run configuration (also making it obvious, traceable) and load the bits from the rule (only affecting the rule loading and using the variable). E.g, BUILD file:
load(":myarray.bzl", "myarray")
foo(
name = "helloworld",
myarray = myarray,
],
)
And you can then call your build:
$ echo 'myarray=[":bar", "//path/to:qux", ":baz", ":another"]' > myarray.bzl
$ bazel run //:helloworld
Which you can of course put in a single wrapper script. If this really needs to be a bazel array, this one is probably the cleanest way to do that.
--workspace_status_command: you can collection information about your environment, add either or both of the resulting files (depending on whether the inputs are meant to invalidate the rule results or not, you could use volatile or stable status files) as a dependency of your rule and process the incoming file in the what is being executed by the rule (at which point one would wonder why not pass it to as its command line arguments directly). If using stable status file, also each other rule depending on it is invalidated by any change.
You can do similar thing by using --action_env. From within the executable/tool/script underpinning the rule, you can directly access defined environmental variable. However, this also means environment of each rule is affected (not just the one you're targeting); and again, why would it parse the information from environment and not accept arguments on the command line.
There is also --define, but you would not really get direct access it's value as much as you could select() a choice out of possible options.

Does the preprocessor pass environment variables?

Does the preprocessor have a mechanism to access environment variables directly as defines, without the need to define them on the command line?
For instance,
SOME_VAR=foo gcc code.c
and
#if ENV_SOME_VAR == "foo"
#define SOME_VAR_IS_FOO
#endif
No, the standard C preprocessor has no such mechanism, and I'm not aware of any compiler extensions that provide such a feature either.
However, you can do this using a build system, such as Cmake or GNU Autoconf, the latter being a part of the GNU Autotools build system. A simple shell script would do this as well, though all of these options mean you'd need to test the environment variable to determine whether to define ENV_SOME_VAR, in which case, you might just define it using something like the following:
-DENV_SOME_VAR="${SOME_VAR:-unfoo}"
That would define ENV_SOME_VAR in your C file as the value of $SOME_VAR if it's set or to the string "unfoo" if $SOME_VAR is empty (null) or unset.

ocaml: Is there an environment variable to set the search path for #use and #load?

I've been wondering, if there is an environment variable to set the search path for #use and #load for the ocaml toplevel.
What I think I know so far:
I can use findlib instead of "raw" #use and #load. findlib looks at some environment variables for the search path.
I can set a search path with -I.
Experiments seem to indicate that CAML_LD_LIBRARY_PATH does not influence #use (script loading) and #load (byte code file loading).
(updated) I can use #directory to add the desired path - but unfortunately this only takes a string literal, so i can't pass something I read from the environment at run time. (Update: I forgot to mention #directory originally and why it doesn't fit my use case).
What I want to do:
Run ocaml programs as scripts
Point ocaml to script libraries and script fragments with an environment variable
Avoid, in some scenarios, to create a full findlib library.
Presently I'm not using ocaml as interpreter, but a wrapper that adds a path to the invocation. I want to avoid the wrapper.
(I hope the questions makes sense now, after you know my use case)
So: Is there an environment variable to set the search path for #use and #load without resorting to a wrapper?
More Details
What I'm currently doing:
#!/usr/bin/env oscript2
#use "MyScript"
#load "SomeModule.cmo"
(* ... more ocaml *)
oscript2 is a wrapper around ocaml that basically sets the search paths for #use and #load, but finally executes the toplevel ocaml withe something like
exec ocaml -I .... ...some-byte-code-modules... "$#"
MyScript and SomeModule.cmo live outside of the "normal" Ocaml search path. The actual location might change, but after login (and working through the profie scripts) there is an environment variable (today it's OSCRIPTLOAD_PATH) that tells me, where alle loadable byte code and ocaml script files might live.
This works well, a variant of that setup has been in use for years (at least 7).
The one thing that bothers me there, is: The wrapper, the simple fact of it's presence, looks homebrew, so I'd like to avoid it, to make a better impression on potential future users of the script collection. What I'd like to do
#!/usr/bin/env ocaml
#use "MyScript"
#load "SomeModule.cmo"
(* ... more ocaml *)
and have ocaml itself pick up the search path from some environment variable (I'm free to change the variable name, that is under my control, but I don't want to install script and byte code libs into the default search path, and, as already stated, I' asking if I can do that without findlib).
Basically (as already stated at the very beginning) I'm looking for an environment variable that controls the search path for #use and #load. I'm not looking for toplevel directives and not for wrappers that retrofit this feature. (Thanks everyone for those suggestions, but unfortunately I've already gone that road, it's feasible, but here I'm looking for an alternative purely for cosmetic reasons).
Recent research didn't bring up that such a variable exists, but I thought I'd be asking here, before giving up on it.
From inside the OCaml toplevel you can use the #directory "foo";; primitive to add an include directory.
Here's a shell script that runs the OCaml toplevel while adding a directory to the search path taken from an environment variable named EXTRA_OCAML_DIR.
#!/bin/sh
ocaml -I "$EXTRA_OCAML_DIR" "$#"
If you run this instead of ocaml, you will have a directory in the load path specified by an environment variable.
It seems a little obvious, but maybe it will spark an idea that is more helpful.

How to set ISPP defines based on default Inno Setup variables?

I was trying to:
#define CommonAppData {commonappdata}
but it yields:
Compiler Error
[ISPP] Expression expected but opening brace ("{") found.
How to achieve this with Inno Setup PreProcessor?
{commonappdata} cannot be expanded at compile time, i.e. when the pre-processor runs because it is only known at runtime: It identifies the common application data directory on the machine where the compiled installer is run.
Maybe if you could clarify how you intend to use that define we might be able to help. If for example what you're really interested in is not the common app data directory on the target machine but the one on the developer machine, then you can probably use this:
#define CommonAppData GetEnv("COMMONAPPDATA")
If however you intend to use that define for populating Inno properties that are themselves capable of expanding the constant at runtime then you should use this:
#define CommonAppData "{commonappdata}"
Hope this helps.
#define is a inno setup pre-processor directive, in a pre-compile phase. It works much like a C pre-processor.
By defining a pre-processor variable, we force the compiler to see a script after the ispp defines are resolved:
Inno Setup Preprocessor (ISPP) is an add-on for Jordan Russell's Inno Setup compiler. More technically speaking, it is an additional layer between GUI (your Inno Setup script) and the compiler, which before passing the text intercepts and modifies it in a way it is told by using special directives in the script text.
That said, I can't find a source in documentation nor have time to digg into the source code, but I'm pretty sure inno setup variables are not available during this pre-compile time.
If you just want the defined variable to contain the string {commonappdata}, use it directly in your source... if you want the defined variable to have the run-time value of commonappdata, it doesn't seem possible to me, because that value is determined at runtime as its current value depends on the target machine (windows version, language, etc.).
If you think it twice, it doesn't make sense to try to use that value at pre-compile or compile time... this is just the whole fact that brings inno setup constants like {commonappdata}, {destdir} and the like to existence... that you can express in a standard way at compile time a unknown but meaningful value, which will be known and evaluated at runtime.
You'll probably need to escape the brace. Something like:
#define CommonAppData {{commonappdata}

Resources