How can I append to a construction variable in a Program() call? - scons

I have a custom environment set up for my tests:
test_env = env.Clone()
test_env.Append(LIBS=['boost_unit_test_framework'])
But for one of my tests, I want to link against an additional library:
test_env.Program('foo_tests',
source='foo/tests.cpp',
LIBS=['extralib'],
LIBPATH=['.'])
Sadly this overrides the LIBS from the environment, when I'd like it to just add to it. Is there a better (i.e. more canonical) way to do this than LIBS=test_env['LIBS'] + ['extralib']?

Specifying a new value for an environment variable in a Builder call (like Program) is always interpreted as an "override". So there is no way around compiling the full replacement value, as you did in your example above.
The other option would be to Clone the environment "test_env" again, and then use Append to add the "extralib" to LIBS...

It's possible to do it like this:
test_env.Program('foo_tests',
source='foo/tests.cpp',
LIBS=['$LIBS', 'extralib'],
LIBPATH=['$LIBPATH', '.'])
SCons is clever enough to properly expand the variable into a list there.

Related

Scons: command-line build variables without restrictions on allowed values

Used Scons version: 3.0.1 (for historic reasons)
I want to add a command-line build variable in my Scons script which is not limited by which values it expects. Both EnumVariable and ListVariable require you to provide a list of allowed values or elements.
I want a variable that (just like a C++ define can be passed to g++ via -Dfoo=bar (or at least -Dfoo_bar) ) can be passed to the Scons script.
Anything like
scons my_define=foo_bar
or
scons my_define=foo=bar,gnarl=argl
or
scons my_define=foo my_define=bar
would work.
I did not find anything like that in the user guide or searching via Google.
Is this possible? If yes, how?
Yes. It's in the users guide at
https://scons.org/doc/production/HTML/scons-user.html#idp140637539360912
While there are validated variable types provided by the various vars.Add*() methods. You can have a non-validated variable by just using plain vars.Add()
Here's an example from the manpage.
vars.Add('CC', help='The C compiler')

How to check for the existence of a header of a package?

In Autoconf, when you want to check for the existence of some header, you do:
AC_CHECK_HEADERS([foo.h])
Now, let's suppose that I have some package, sponge, of which pkg-config knows, and I want to find out if it has a header named spongefoo.h.
I can do the following:
PKG_CHECK_MODULES([SPONGE])
CPPFLAGS="$CPPFLAGS $SPONGE_CFLAGS"
AC_CHECK_HEADERS([spongefoo.h])
This would work, but the Autoconf/Automake documentation says (my additions in brackets):
"Sometimes package developers are tempted to set user variables such as 'CFLAGS' [and, I add, 'CPPFLAGS'] because it appears to make their job easier. However, the package itself should never set a user variable, [...] To get around this problem, Automake introduces an automake-specific shadow variable [named AM_CPPFLAGS]"
However, AC_CHECK_HEADERS() and other test macros don't know about Automake's shadow variables.
So how do I properly check that a package has some header?
(BTW, AC_CHECK_HEADER() gets a 4'th argument, "INCLUDES", but this is a verbatim '"#include"' text, not a '"-I..."' switch, so it doesn't help me much.)
The requirement to temporarily set a user variable like CPPFLAGS to some value and run a compilation test while preserving the original value is actually done quite often. This is usually accomplished in Autoconf using a pattern similar to the following:
ac_save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $SPONGE_CFLAGS"
AC_CHECK_HEADERS([spongefoo.h])
CPPFLAGS=$ac_save_CPPFLAGS
Note that the ac_ shell variable prefix is informally reserved for Autoconf itself, you might want to use your own variable name like proj_save_CPPFLAGS.

autoconf/automake: conditional compilation based on presence of library?

I need to conditionally compile some code based on the presence of a library. Seems like this should be easy with autoconf/automake but I can't figure it out.
For example, if there is a PNG library present, I want to include code to use it. My configure.ac has:
AC_CHECK_LIB([png], [png_create_write_struct_2])
and my Makefile.am has:
if USE_LIBPNG
libdev_la_SOURCES += png.c
endif
(which adds png.c to the list of sources for libdev so it gets compiled).
An automake conditional like USE_LIBPNG requires the conditional be defined in configure.ac, so i need:
AM_CONDITIONAL([USE_LIBPNG], [test SOMETHINGOROTHER])
The question is, what can test SOMETHINGOROTHER be? What does AC_CHECK_LIB define that I can test for?
AC_CHECK_LIB's default behavior is to define a symbol (in config.h) which can be used in source code, but that doesn't help the Makefile since the AM_CONDITIONAL needs a shell test
I tried overriding the default AC_CHECK_LIB behavior like so:
AC_CHECK_LIB([png], [png_create_write_struct_2], [HAS_LIBPNG=1])
after which I could test for it:
AM_CONDITIONAL([USE_LIBPNG], [test "x$HAS_LIBPNG" = "x1"])
This is ugly, but works for the Makefile... but creates a new problem: since it discards the original AC_CHECK_LIB behavior, and I no longer get a symbol added to config.h, which I need.
I must be missing something basic, or possible Doing It Wrong. Have been digging around for hours and found no answer.
Anyone?
If the library you're checking for supplies a .pc file for use with pkg-config, then you're much better off using PKG_CHECK_MODULES to get the correct flags. libpng does:
(in configure.ac)
PKG_CHECK_MODULES([libpng], [libpng12])
This gives you access to the variables $(libpng_CFLAGS) and $(libpng_LIBS) which you will want to add to Makefile.am (probably in AM_CFLAGS/AM_CXXFLAGS and LDADD, or target-specific versions thereof).
It will also cause configure to fail with an error if libpng12.pc isn't found. If you want configure to continue, you'll need to supply the third and fourth arguments to PKG_CHECK_MODULES, which are ACTION-IF-FOUND and ACTION-IF-NOT-FOUND:
(in configure.ac)
PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])
Now, if you need an automake conditional, you can do something like:
(in configure.ac)
AM_CONDITIONAL([USE_LIBPNG], [test "$HAVE_LIBPNG" -eq 1])
If you also need the preprocessor definition, you could use AC_DEFINE like so:
(in configure.ac)
AS_IF([test "$USE_LIBPNG" -eq 1], [AC_DEFINE([USE_LIBPNG], [1], [Define if using libpng.])])
Possibly nicer is to set the definition in Makefile.am:
(in Makefile.am)
AM_CPPFLAGS =
if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
endif
This will clutter your command line, though, whereas AC_DEFINE can put the definition in a header if you use AC_CONFIG_HEADERS. I guess this doesn't really matter if you use AM_SILENT_RULES([yes]) or don't care about your command line being neat (and let's be honest, automake generates some pretty gnarly command lines anyway).
A note on good autoconf style
It is considered poor form to build optional support based on whether or not a check succeeded (see this gentoo doc for details). Here's how I'd code optional support for libpng:
(in configure.ac)
# This is because the first PKG_CHECK_MODULES call is inside a conditional.
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([libpng],
[AS_HELP_STRING([--with-libpng],
[support handling png files #<:#default=check#:>#])],
[],
[with_libpng=check])
AS_CASE(["$with_libpng"],
[yes], [PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1])],
[no], [],
[PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])])
AM_CONDITIONAL([USE_LIBPNG], [test "$with_libpng" != no -a "$HAVE_LIBPNG" -eq 1])
(in Makefile.am)
if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
AM_CFLAGS += $(libpng_CFLAGS)
LDADD += $(libpng_LIBS)
libdev_la_SOURCES += png.c
endif
If your library doesn't have a .pc file
For completeness, here's how I'd check for a library that didn't have a .pc file. I'll skip over the details of following good autoconf style. AC_CHECK_LIB sets a cache variable, so you can test that instead of replacing the ACTION-IF-FOUND of AC_CHECK_LIB:
(in configure.ac)
AC_CHECK_LIB([png], [png_create_write_struct_2])
# Then test:
AS_IF([test "$ac_cv_lib_png_png_create_write_struct_2" = yes], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])
# Or set conditional:
AM_CONDITIONAL([USE_LIBPNG], [test "$ac_cv_lib_png_png_create_write_struct_2" = yes])
IMHO, you should only do it this way if you have no other option.
I will disagree mildly with Jack on his recommendation to use PKG_CHECK_MODULES. It is probably best to avoid using that. But I will agree with Jack on avoiding assigning to LIBS in the 3rd argument to AC_CHECK_LIB. Life is easier if you let AC_CHECK_LIB use the default settings.
Although AC_CHECK_LIB does not define a shell variable indicating whether or not the library was found, you can do this in configure.ac:
AM_CONDITIONAL([USE_LIBPNG],[grep HAVE_LIBPNG confdefs.h > /dev/null])
Arguably, this is relying on internal autoconf details, but in practice will work reliably.
Thanks for the replies.
Jack: I'm trying for maximum portability, so can't assume the libraries were installed as part of a package (they're not on my own box!), which means the no-other-option solution you suggested is what I already tried-- setting a shell variable manually-- but also manually performs the extra steps that would have been done by AC_CHECK_LIB: prepending the library to LIBS and defining HAVE_LIBxxx.
There was a catch though: autoheader complains about the bare AC_DEFINE:
autoheader: warning: missing template: HAVE_LIBPNG
autoheader: Use AC_DEFINE([HAVE_LIBPNG], [], [Description])
I'd be nice if autoheader worked in the future, so I had to change AC_DEFINE to the full monty:
AC_CHECK_LIB([png], [png_create_write_struct_2],
[HAS_LIBPNG=1
LIBS="-lpng $LIBS"
AC_DEFINE([HAVE_LIBPNG], 1, [Define to 1 if you have the `png' library (-lpng)])])
This works, but I don't much like having to duplicate the default behavior of AC_CHECK_LIB.
William: Yes I could grep for the symbol definition in confdefs.h, that also works.
Both solutions have their pros and cons (what doesn't?). Not sure which way I'll go, but it's nice to have options.
Thanks again.

How to write a path that include environment variables?

I'm writing a Qt app that runs in Linux. I need to write a file to:
"$XDG_CONFIG_DIRS/whatever"/ "$HOME/whatever"
How do I resolve the environment variables ## Heading ##in my code?
Using nothing but plain library functions, you use getenv() to look up the value of environment variables:
const char *dirs = getenv("XDK_CONFIG_DIRS");
This will return NULL if the variable was not set in the environment, so make sure your code handles this case.
You'll have to do the "interpolation" of the variable values into the rest of the text yourself, in that case.
Not sure if Qt provides a wrapper or something more high-level that can do the interpolation for you, I haven't worked with Qt.
getenv, as already mentioned, if you really only target Linux. If you want it portable to Non-Unix platforms, you should use qgetenv() or QProcessEnvironment::systemEnvironment().value(QLatin1String("XDG_CONFIG_DIRS")). In general, it's good practice to use the portable Qt way.

Visual C++ preprocessor definitions

Is there a way to transfer C++ preprocessor definitions into a custom pre-link step procedure call as a command-line parameter or export them into a file any other way?
Example:
Let's say, I have a c++ project, and in it's Debug configuration I put a preprocessor definition like MAKUMBA_OBA=0x13
Then I add custom pre-link step which executes some javascript like
sarahjessicaparker.js /to tomsrhinoplasty $(MAKUMBA_OBA)
It would be great, if it just worked, but I never get a third parameter in my js. So the question is: how to pass a preprocessor definition to s script?
There is no way to do such a thing. The only acceptable solution is to analyze the build profile name and act accordingly.

Resources