[Scons-users] Source paths across external projects
Bill Deegan
bill at baddogconsulting.com
Thu Sep 8 21:27:05 EDT 2016
Bobby,
How about:
In the example above, `top_project/SConscript' would look like this:
src = SConscript('sources.scons')
foo =SConscript('extern/foo/sources.scons')
src.extend(foo)
prog = Program('test', src)
and `extern/foo/sources.scons' would look like this:
src = [File('src/foo.c')]
Return('src')
Or:
src = [SharedObject('src/foo.c')]
Return('src')
On Thu, Sep 8, 2016 at 11:15 AM, Bobby Casey <beecee808 at gmail.com> wrote:
> Hello,
>
> I'm going to start by apologizing for the length of this email. I started
> off trying to explain what I'm looking for and what I have done and ended
> up trying other ideas as I went along.
>
> So here's what I'm trying to do - I have a project that depends on several
> external source repositories. The structure looks something like this:
>
> top_project/
> ---> SConstruct
> ---> SConscript
> ---> sources.scons
> ---> extern/foo
> ------> SConstruct
> ------> SConscript
> ------> sources.scons
> ------> src/
> ---------> foo.c
> ---> extern/bar
> ......
>
> Where each of the "extern" projects (there are several) is a separate
> repository that is capable of building itself (generally for testing
> purposes) and contains a sources.scons file that top_project's SConscript
> file pulls in to grab the list of source files that the sub-project
> provides. The problem, however, is that when `top_project/SConscript' calls
> `SConscript("extern/foo/sources.scons")', all the paths are relative to
> top_project (rather than extern/foo).
>
> This is a bit hard to explain, let me give a visual.
>
> In the example above, `top_project/SConscript' would look like this:
> src = SConscript('sources.scons')
> foo =SConscript('extern/foo/sources.scons')
> src.extend(foo)
> prog = Program('test', src)
>
> and `extern/foo/sources.scons' would look like this:
> src = ['src/foo.c']
> Return('src')
>
> This will fail with the following error:
> scons: *** [build/src/foo.o] Source `build/src/foo.c' not found,
> needed by target `build/src/foo.o'.
>
> That is, of course, the correct behavior - just not the behavior what I
> wanted! I could prepend os.path.abspath before each file, but that leaves
> the object files next to the sources, ignoring any variant_dir that was
> specified in top_project/SConstruct.
>
> I worked around this by modifying top_project/SConscript to look like this
> instead:
> def add_scons_source(proj_dir):
> src = SConscript('%s/sources.scons' % proj_dir)
> src = ['%s/%s' % (proj_dir, s) for s in src]
> return src
>
> src = SConscript('sources.scons')
> src.extend( add_scons_source('extern/foo') )
> prog = Program('test', src)
>
> This prepends the appropriate path to each source file and works just fine
> but feels decidedly "unsconsy". I then considered having each
> sources.scons be responsible for building it's own object files and that
> works great. It's exactly what I wanted for building the application. I
> suspect this is also the canonically correct way to do it. The problem is
> that, in our real application, we also have a lint target that needs to be
> run against all source files so that it can detect issues across
> compilation units. I'd like to avoid having the external projects know
> anything about lint, or whatever other targets are available in the
> top_project, so I came up with this as a possible solution.
>
> top_project/SConscript would look something like this:
> env = Environment()
> source_list = []
> def do_lint(target, source, env):
> print 'running lint on %s' % (str(s) for s in source)
>
> def aggregate_sources(target, source, env):
> global source_list
> source_list.extend( [str(s) for s in source] )
>
> env.Append(BUILDERS={'AggregateSources': Builder(action=aggregate_
> sources)})
> env.Append(BUILDERS={'LintBuilder': Builder(action=do_lint)})
>
> SrcBuilder = env.Object
> src = SConscript('sources.scons', exports=['SrcBuilder'])
> src.extend( SConscript('extern/foo/sources.scons',
> exports=['SrcBuilder']) )
>
> prog = env.Program('test', src)
> Default(prog)
>
> SrcBuilder = env.AggregateSources
> lint_src = SConscript('sources.scons', exports=['SrcBuilder'])
> lint_src.extend( SConscript('extern/foo/sources.scons',
> exports=['SrcBuilder']) )
> lint = env.LintBuilder('lint.out', lint_src)
>
> Alias('lint', lint)
>
> and the sources.scons files would all look something like this:
>
> Import('SrcBuilder')
> src = ['src/foo.c']
> built = [SrcBuilder(s) for s in src]
> Return('built')
>
> This looks a bit silly in this contrived example because the SrcBuilder
> would really be part of two separate environments (one for Program and one
> for Lint targets), but I think you get the point. The advantage to this
> method is that the builder is provided to sources.scons so it need not know
> how we're using the sources but can still handle them appropriately. The
> disadvantage is that SrcBuilder needs to either be some common name for two
> wildly different things that are either part of the environment or passed
> as an extern. It would be nicer if I could say something like `export(
> env.Object as "SrcBuilder")' and `export( env.AggregateSources as
> "SrcBuilder")'. Is there some way to do this?
>
> I would appreciate any comments/feedback/suggestions/criticism. Are any
> of these methods even remotely sound? Is there some canonical way of doing
> this that I have just totally missed somehow? Am I proposing a flawed
> architecture that could be easier/better done in some other way?
>
> Thanks in advance,
> Bobby
>
>
> _______________________________________________
> Scons-users mailing list
> Scons-users at scons.org
> https://pairlist4.pair.net/mailman/listinfo/scons-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://pairlist4.pair.net/pipermail/scons-users/attachments/20160908/7afbe82b/attachment-0001.html>
More information about the Scons-users
mailing list