Multiple locations within a folder hierarchy to run SCons from - scons

So far, I've only seen examples of running SCons in the same folder as the single SConstruct file resides. Let's say my project structure is like:
src/*.(cpp|h)
tools/mytool/*.(cpp|h)
What I'd like is to be able to run 'scons' at the root and also inside tools/mytool. The latter compiles only mytool. Is this possible with SCons?
I assume it involves creating another SConstruct file. I've made another one: tools/mytool/SConstruct
I made it contain only:
SConscript('../../SConstruct')
and I was thinking of doing Import('env mytoolTarget') and calling Default(mytoolTarget), but running it with just the above runs in the current directory instead of from the root, so the include paths are broken.
What's the correct way to do this?

You can use the -u option to do this. From any subdirectory, scons -u will search upwards in the directory tree for an SConstruct file.

Related

SCons: When adding a Node to the LIBS variable, how do I make it use just the file without the directory?

I have SCons code in which I am using SConscripts to build different directories separately. In my Src directory, my SConscript builds a shared library, and then returns the resulting Node as the Python variable libMyLibrary. I typically use the install option to copy this library to a directory that is on my system's LD_LIBRARY_PATH (I'm using OpenSUSE).
So far, so good. Now, in another directory, Src/Test, another SConscript imports libMyLibrary and builds some Programs using code like this:
env.Program('myProgram', 'myProgram.cpp', LIBS=[env['LIBS'], libMyLibrary])
The program then gets installed to my local bin folder. This code does track the library dependency and build the program, but the problem is that since the library is in a sub-directory (Src), that sub-directory gets included in the linker command. Here is an abbreviated example of the linker command that SCons generates:
g++ -o Src/Test/myProgram Src/Test/myProgram.o Src/libMyLibrary.so
I believe this happens because the Node,libMyLibrary, is essentially a path. The problem is that when I try to run the program, it is not looking for libMyLibrary.so in my library folder, but rather Src/libMyLibrary.so, and of course it doesn't find it.
I do NOT want the libraries I build to be installed in sub-directories of my install folder.
I already add the Src folder to LIBPATH, so SCons adds the -LSrc option to the linker command, but that doesn't solve the problem. My preference would be that when I add a Node, the path should automatically get parsed out to add the appropriate -L and -l options.
I know that I can get around this problem by adding the string 'MyLibrary' to the LIBS variable instead of the libMyLibrary Node, but then I have to explicitly tell SCons that each Program Depends() on libMyLibrary. It seems very inefficient to short-circuit SCons's built-in dependency tracking this way. Does anyone know the correct, SCons-y way to do this?
I'm referring to your latest comment: It looks to me as if this is not really a SCons problem, but more a general linker question (XY problem). Are you perhaps simply searching for RPATH? Please also check this old SO question: scons executable + shared library in project directory

Including extra directories with Keter

I have a Yesod site and have created a handler for handling downloads and enforcing constraints. My Yesod project directory has a subdirectory called downloads, and it contains files I want the user to be able to download if they are logged in. The handler works great in my development and staging boxes, but breaks when I transfer to production. I tracked the problem down to yesod keter not archiving the files when it builds its bundle.
How do I convince keter to include the directory?
All the yesod keter command does is create a .tar.gz compressed archive file with the .keter extension containing the following subdirectories:
config: an exact copy of the identically named directory in your source tree
dist: contains a subdirectory bin containing your app's binary
static: an exact copy of the identically named directory in your source tree
Note that the path to your app's binary is set in config/keter.yml via the exec setting while the path to your static files is set via the root setting. The exact set of files included by the yesod keter command is specified in the findFiles function if you want to take a look at the source code.
If you want to customize the contents of your .keter file it is probably most straightforward to write a shell script to create the archive. With this script you can add arbitrary extra directories to the archive.
The bare minimum bash script you'd need to emulate the behaviour of yesod keter is as follows:
#!/bin/bash
tar cvf myapp.keter config/ dist/bin/ static/
You can customize this however you want to produce the correct content. Adding download/ to the end of this command line should do the trick.

SCons: Forcing SCons to duplicate files

I have a header-only library consisting of a folder hierarchy and a bunch of .hpp files I'd like to install. My problem is, that scons does not copy the folder into the build folder.
Here is what my directory layout looks like:
root
SConstruct
subdir
SConscript
the_lib
subdir_a
header_a.hpp
subdir_b
header_b.hpp
build
(...)
Here is what I do in subdir/SConscript:
all_headers = []
for root, dirnames, filenames in os.walk('.'):
for filename in fnmatch.filter(filenames, '*.hpp'):
fn = os.path.join(root, filename)
all_headers.append((fn, root))
for f, d in all_headers:
install.AddHeader( f, d )
I do this to get the filenames along with their relative paths and then, I use the installer I found in the scons wiki the other day.
Observation: all_headers remains empty because the the_lib folder does not get copied. I tired subdir_env.Dir('the_lib'), but did not change a thing.
After running the script, I have the_lib/SConscript in my build folder, but nothing else. Of course I can understand that my filesystem walk does nothing in that case.
Can anyone help me?
UPDATE
The only way out I found was to run a find -name "*.hpp" and paste the result into my SConscript. Works like a charm now, but since the library is an external one (and maybe some files are added or removed), I thought of a more generic solution without the need to know all headers by name.
The first thing I thought of was to use the SCons Install() builder, but that is to install actual SCons targets in different locations, and since these header files are not targets, that wont work.
So, in this case, you can use what is called the SCons Copy Factory.
if build is a VariantDir then you don't need to copy the file yourself, scons will do it if the header is used in any Builder.
If you want to a list of the files you can use env.Glob('*/*.hpp') (but wildcards won't traverse directories, so you need to know the depth)

Building relative to src/ directory with SCons

I have an app with the following (I would have thought quite common) directory hierarchy:
/src
subdir1/ # Subdirs with more source files.
more.c
SConscript
foo.c # Source files.
foo.h
SConscript
/other # Other top-level directories with no source code.
/stuff # However, there are other assets I may want to build.
README # Other top-level files.
SConstruct
The problem is that when I run scons from the top-level directory, it calls gcc from that directory without cding into src, like this:
gcc -o src/foo.o src/foo.c
This is problematic for several reasons:
Within my program, I #include files giving the path relative to the src directory. For example, more.c could include foo.h with #include "foo.h". This fails because GCC is run from the parent directory. I don't want to change my includes to #include "src/foo.h".
I use the __FILE__ special macro for things like logging. When built from the top-level directory, GCC puts "src/" at the front of all filenames, since that was the path it was given to compile. This may seem picky, but I don't want that, because I think of my source tree as being relative to the src directory.
(Edit: I should add that obviously #1 can be fixed by adding -Isrc as a flag to GCC, but this seems like more hacks around the main issue.)
How can I make SCons cd into the src directory before calling gcc?
I don't want to get rid of the src directory and move everything up, because there are lots of other (non-code) files at the top level.
I don't want SCons to cd into every subdirectory. It should just cd into src and then build all files in the hierarchy from there.
I could solve this by moving SConscript inside the src directory and running it from there, perhaps using a Makefile at the top level. But this seems quite hacky, and I also do want to use SCons to build (non-code) assets in other directories than src.
I've read that you can make a custom Builder and make it change directories. However, I do not want to write a whole new Builder for C/C++. Is there a way to modify the behaviour of an existing builder without writing one from scratch? Also, on one forum, someone said that changing directories from within a Builder would break parallel builds since it would change the directory that other tasks are building from. Is this true?
This behavior is just how SCons works, and its not possible to avoid/change. I've been looking for some supporting documentation in its favor, and havent found any. Its just something Ive become used to.
As you mention, the include paths are simple to fix. The harder part is the __FILE__ macro. I hadnt ever noticed this until you mentioned it. Unfortunately, I think the only way around this is to strip the path in the logger, which is a rather ugly fix.
You can add src to your env['CPPPATH'] which will fix the include paths.
env.Append(CPPPATH=[Dir('src')])
However, this doesn't solve the problem with __FILE__.

How can Scons be setup to output directories above where the sconstruct is?

I have a folder structure similar to the following:
Project
-----src
--------lib
-----bin
--------Debug
-----scons
My sconstruct and sconscripts are in the "scons" folder. What I would like to do is take the build output from my lib folder and place it into the bin/debug folder. I've tried doing something like this:
Sconstruct:
VariantDir('../bin/Debug','.')
lib = SConscript('libSconscript')
Sconscript:
env.StaticLibrary('../bin/Debug/lib', Glob('../src/lib/*.cpp'))
But that does not seem to work. From the man page, it sounds like VariantDir() would work as I've done it, but it does not seem to. If anything, it either doesn't build at all or builds in the current directory. Anyone point out what I'm doing wrong?
I apologize if any of this is confusing. Keeping track of all these directories in a sconscript is more difficult than one would think it would be.
Currently SCons doesnt support this. The SConstruct has to be at the root level of the project. That is, you will need to do the following:
Project
-----SConstruct
-----src
--------lib
-----bin
--------Debug

Resources