0

I'm trying find the best way to replicate Makefile's include in SConstruct. I have come up with a solution, but its messy, relies of the user passing in specific command-line parameters and surely can't be the best option.

My file structure is as so:

Working_Dir/
   |-> includes/
   |    |-> filename.mk
   |    |-> filename.py
   |-> Makefile
   |-> main.c
   |-> SConstruct

These are my file's contents

Makefile

all: main.o
    echo "Version is: $(VERSION)"
    gcc $^ -o main

include includes/filename.mk

filename.mk

VERSION := "1.6.2"

%.o: %.c
    gcc -c -o $@ $<

SConstruct

import filename

env=Environment()
filename.Init(env)

#Create new builder
prog = Builder(action=["gcc $SOURCE -o $TARGET"])

#Add the builder
builder = { "Prog": prog}
env.Append(BUILDERS=builder)

print "Version is: " + env['VERSION']
env.Prog(target = "main", source = "main.o")

filename.py

from SCons.Script import *  # Needed so we can use scons stuff like builders

def Init(env):
    #Make builder
    obj = Builder(action="gcc -c -o $TARGET $SOURCE")

    #Add stuff
    env.Append(BUILDERS= {'Obj': obj})
    env.Append(VERSION= "1.6.2")

(Ignore the fact that SCons has its own Object builder, this is just a simplified example that I made to learn from for a bigger project)

To compile with the makefile I run make and for SCons its scons --site-dir="includes" since my included file isn't in the standard path. As far as I'm aware the site_dir option is the only way to include your own code/builders in scons as seen here. Also note that SConscript files aren't what I want, since when you call them they execute their instructions in their own directory rather than just loading variables and builders into the caller.

I want it to the user can just run scons and it works. I have read I can set these settings globally to my bash profile as seen here in section 10.1.1, but I don't want to do this because I don't want every SCons project on my system defaulting to use this directory. I also had a look at the SetOption() function, but its limited and doesn't actually allow you to set this particular parameter at all.

The only solution I can think of is to start off using GetOption('site_dir') and if its not the directory I'm expecting, I invoke a new SCons call with all of the same parameters, but now with the correct site_dir option.

However this feels very ghetto and I feel I'm missing a much better solution. Is there a better solution?

EDIT:

The reason I'm using this "includes" directory instead of the "site_scons" directory is because in my larger project the "includes" directory isn't in the same directory as the project, its in a completely different directory (The path to that directory is known). filename.py will be used for multiple of my SCons projects that depend on it, but not every SCons project on my machine should use it (ie. It shouldn't be global).

bad_coder
  • 11,289
  • 20
  • 44
  • 72
Protofall
  • 612
  • 1
  • 6
  • 15
  • 1
    Why is renaming the `includes` folder to `site_scons` not an option? – dirkbaechle May 14 '19 at 13:47
  • If you can explain why site_scons is not an option for you, then perhaps we can come up with a reasonable answer. – bdbaddog May 14 '19 at 17:16
  • My bad, I misunderstood `site_scons` as a global system folder where every SCons project has access to it instead of it being just for the local project. My problem still exists and I've updated the description to clarify the behavior of my system (Edit section). – Protofall May 15 '19 at 00:30
  • But how can *SCons* know which of your projects may depend on the global/local definitions? I don't see a way around some form of command line switch, or a global lookup table which lists the available projects together with their special config settings. I'm not talking about any specific details, but just from a high-level perspective. If you expect some projects to be treated different than others, how is *SCons* supposed to know...without the user providing the required infos? – dirkbaechle May 15 '19 at 08:43
  • When using *make* for your "larger" project, how does it know that it shouldn't search in a local "includes" folder but in a different directory somewhere else on the hard-drive? Thinking more in the direction of config files (Python has excellent direct support for that) for keeping data like program versions and such might be the way to go... Then you can give the hardwired path to the config file in each `SConstruct` to your `filename.Init()`. – dirkbaechle May 15 '19 at 08:51
  • `filename.py` is a part of library I'm making. As part of the setup for my library, the path to the library must be added to the bash profile `export LIB_BASE="/path/to/my/library/directory"`. Within this folder there is a folder called "rules" and that contains my `filename.py` file. I have a few projects that use my lib and I want to add extra rules and variables from `filename.py` to my SCons files. If this was a Makefile I would add `include "$LIB_BASE/rules/filename.py"` to all the projects I want to use this in. Your config idea might work, but I don't know how to do that. – Protofall May 15 '19 at 13:42
  • https://wiki.python.org/moin/ConfigParserExamples – dirkbaechle May 15 '19 at 14:30
  • That...doesn't work? I got the first example working (Reading the file and correctly listing the 4 section names), but I don't think this will work for my program. The link showed a function they defined which seems to be a part of the caller function, not the ini file. Based on the examples from that link it seems config files can *only* store variables and not functions/builders. I need to be able to load builders in to so I don't think config files will work. – Protofall May 16 '19 at 02:41

1 Answers1

0

I figured it out on my own. I just loaded the file as a normal python module as seen in the top answer here. I specifically used the Python 2 answer since it seems SCons is configured on my system to use python 2.

Thanks to this I have the ability to load any python file including scons related code from anywhere on my computer, this is exactly what I wanted.

For those curious, here's the code I needed to add

file_path = "/path/to/my/file/filename.py"

import imp
extra_stuff = imp.load_source('filename', file_path)

env=Environment()
extra_stuff.Init(env)
Protofall
  • 612
  • 1
  • 6
  • 15
  • `import includes.filename` should be enough though – Zoe May 29 '19 at 19:17
  • 1
    As mentioned in the edit section, that solution won't work because it only works when `includes` is in the same directory as the calling script (My SCons file). For my usage I must assume the `includes` directory's location is anywhere on the computer. – Protofall May 31 '19 at 11:54