Does the preprocessor pass environment variables? - preprocessor

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.

Related

Rename environment variable key

I have following environment variable OLD_KEY=value and want to rename the env var name so it is KEY=value.
Already tryied export KEY=${${OLD_KEY}}.
Anyone who has an idea?
Is a POSIX shell, like bash, you dereference a variable with a single dollar-sign. So this is all you need:
export KEY="$OLD_KEY"
The double-quotes are always a good idea, even if you don't think they're needed due to quirks of the POSIX shell standard. Specifically, how variable expansion interacts with $IFS.
P.S., You should have told us which shell (or language) you're using rather than make us guess.

Default, platform specific, Bazel flags in bazel.rc

I was wondering if its possible for platform-specific default Bazel build flags.
For example, we want to use --workspace_status_command but this must be a shell script on Linux and must point towards a batch script for Windows.
Is there a way we can write in the tools/bazel.rc file something like...
if platform=WINDOWS build: --workspace_status_command=status_command.bat
if platform=LINUX build: --workspace_status_command=status_command.sh
We could generate a .bazelrc file by having the users run a script before building, but it would be cleaner/nicer if this was not neccessary.
Yes, kind of. You can specify config-specific bazelrc entries, which you can select by passing --config=<configname>.
For example your bazelrc could look like:
build:linux --cpu=k8
build:linux --workspace_status_command=/path/to/command.sh
build:windows --cpu=x64_windows
build:windows --workspace_status_command=c:/path/to/command.bat
And you'd build like so:
bazel build --config=linux //path/to:target
or:
bazel build --config=windows //path/to:target
You have to be careful not to mix semantically conflicting --config flags (Bazel doesn't prevent you from that). Though it will work, the results may be unpredictable when the configs tinker with the same flags.
Passing --config to all commands is tricky, it depends on developers remembering to do this, or controlling the places where Bazel is called.
I think a better answer would be to teach the version control system how to produce the values, like by putting a git-bazel-stamp script on the $PATH/%PATH% so that git bazel-stamp works.
Then we need workspace_status_command to allow commands from the PATH rather than a path on disk.
Proper way to do this is to wrap your cc_library with a custom macro, and pass hardcoded flags to copts. For full reference, look at envoy_library.bzl.
In short, your steps:
Define a macro to wrap cc_library:
def my_cc_library(
name,
copts=[],
**kwargs):
cc_library(name, copts=copts + my_flags(), **kwargs)
Define my_flags() macro as following:
config_setting(
name = "windows_x86_64",
values = {"cpu": "x64_windows"},
)
config_setting(
name = "linux_k8",
values = {"cpu": "k8"},
)
def my_flags():
x64_windows_options = ["/W4"]
k8_options = ["-Wall"]
return select({
":windows_x86_64": x64_windows_options,
":linux_k8": k8_options,
"//conditions:default": [],
})
How it works:
Depending on --cpu flag value my_flags() will return different flags.
This value is resolved automatically based on a platform. On Windows, it's x64_windows, and on Linux it's k8.
Then, your macro my_cc_library will supply this flags to every target in a project.
A better way of doing this has been added since you asked--sometime in 2019.
If you add
common --enable_platform_specific_config to your .bazelrc, then --config=windows will automatically apply on windows hosts, --config=macos on mac, --config=linux on linux, etc.
You can then add lines to your .bazelrc like:
build:windows --windows-flags
build:linux --linux-flags
There is one downside, though. This works based on the host rather than the target. So if you're cross-compiling, e.g. to mobile, and want different flags there, you'll have to go with a solution like envoy's (see other answer), or (probably better) add transitions into your graph targets. (See discussion here and here. "Flagless builds" are still under development, but there are usable hacks in the meantime.) You could also use the temporary platform_mappings API.
References:
Commit that added this functionality.
Where it appears in the Bazel docs.

Optional Environment Arguments to SCons Builders

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.

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}

Preserving environment variables in CMake

I am working on something that requires some header files from a different source tree. For various reasons, I would like to keep these headers outside of my project and reference them during the make process.
I have a CMake build script that generates my makefiles, but I would like to be able to generate makefiles with references to environment variables in them, such that the generated makefile can be run like so:
HEADERS=/somewhere/on/the/filesystem make
Is this possible using CMake? Failing that, is there a way to get what I'm after using CMake only?
This seems to have worked for me:
set(${PROJECT_NAME}_PORT "$(TARGET_SERIAL_PORT)")
It's a real-world example but I hope it gives you an idea. You can assign a string to a variable which will be copied verbatim to the Makefile.
You should look at add_custom_command using the TARGET and PRE_LINK options.
You can use $ENV{VARIABLE} to get the value of an environment variable, but it will only be evaluated during the cmake run and not during the make.
For passing environment variable to make, you can:
CMAKE_POLICY(PUSH)
CMAKE_POLICY(SET CMP0005 NEW)
ADD_DEFINITIONS(-DHEADER=$ENV{HEADER})
CMAKE_POLICY(POP)
Replace HEADER to whatever your variable name.
Setting cmake policy CMP0005 is for cmake to generate correct escape for you.

Resources