Discussion:
[Scons-users] Per target env variables
Jonathon Reinhart
2018-09-06 00:09:02 UTC
Permalink
Hi Richard,

You're correct that this syntax will override the variable (via an
OverrideEnvironment), effectively replacing it:

env.Program('hello', 'hello.c', CFLAGS=['-Os'])

I wish something like this would exist, but it's not valid Python syntax:

env.Program('hello', 'hello.c', CFLAGS+=['-Os'])

The best method I've found is this:

env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)

Alternatively, you can clone the environment to customize it for a set
of similar targets:

foo_env = env.Clone()
foo_env.Append(CFLAGS=['-Os'])
foo_env.Program('hello', 'hello.c')

Do note that Clone() is expensive, and should be avoided in my
opinion. If you're not doing anything too crazy, you can get by with
an OverrideEnvironment:

envo = env.Override(
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
envo.Program('hello', 'hello.c')

Note: Don't try to Append() to an OverrideEnvironment; that call is
proxied to the underlying environment which would then be modified.
(This is possibly a bug.)

Hope this helps,
Jonathon
Hi,
I was wondering, I know standard Makefiles have a way of specifying flags for a given file before the target / rule is defined
such as
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
is this possible in scons? or is the only way to pass in custom env variables per target is when the target is defined?
https://www.scons.org/doc/latest/HTML/scons-user/ch03s09.html
such as
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
Also the way the docs read I think it doesn't make it clear if your appending or replacing values in the environment variable (e.g. CFLAGS) for that specific target (I'm assuming replacing)
I've been trying to see if I could port the Makefiles from micropython across to scons btw, but as an initial step I've been trying to keep the logic the same without changing the order of things too much
Many Thanks
Richard
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Bill Deegan
2018-09-06 03:57:38 UTC
Permalink
Don't use something which is not in the manpage.
It can be dropped without warning.

If you're going to use the modified CFLAGS as below many times
Then using Clone() is reasonable.

So here's what I'd sugguest:
env=Environment(tools=[], MY_FLAG='ABC DEF')
env2=env.Clone(MY_FLAG="$MY_FLAG XYZ PQR")

print env['MY_FLAG']
print env2['MY_FLAG']

Here's the output you'd get from such:
scons: Reading SConscript files ...
ABC DEF
ABC DEF XYZ PQR
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.

If you were only doing this for one target then:
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
(Jonathon Reinhart this is a bit simpler than the method you're
recommending)

Should do the trick.

Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start seeing
memory and speed impacted.

If you need to modify a flag, only for a single target, or a handful, and
especially in your case where you want to programmatically convert a
makefile which does such, then regular overrides are fine:
I'm talking about this:
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")


BTW if you get anything functional we'd be happy to pull it into:
https://github.com/SCons/scons-contrib

-Bill
SCons Project Co-Manager
Thanks for the info
I was wondering if there might have been a per target / file thing like
with Require()
I think I'll use the Override example you've given above to use an
OverrideEnvironment()
that seems to be the best way
this seems to work
env2 = env.Override(
{'CFLAGS': env.get('CFLAGS', []) + ['-Os']}
)
I think the Override method isn't documented in the user manual / man page
list of functions from the looks of things.
For info I started writing a script to convert Makefiles to scons scripts
it's still very crude at this stage, and mostly tries to capture variable
assignments and if blocks (not so much the rules) just to try and take out
the majority of the leg work, still someone might find it usefull
https://github.com/grbd/Scons.Make2Scons
Many Thanks
Richard
On Thu, 6 Sep 2018 at 01:09, Jonathon Reinhart <
Post by Jonathon Reinhart
Hi Richard,
You're correct that this syntax will override the variable (via an
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
env.Program('hello', 'hello.c', CFLAGS+=['-Os'])
env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
Alternatively, you can clone the environment to customize it for a set
foo_env = env.Clone()
foo_env.Append(CFLAGS=['-Os'])
foo_env.Program('hello', 'hello.c')
Do note that Clone() is expensive, and should be avoided in my
opinion. If you're not doing anything too crazy, you can get by with
envo = env.Override(
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
envo.Program('hello', 'hello.c')
Note: Don't try to Append() to an OverrideEnvironment; that call is
proxied to the underlying environment which would then be modified.
(This is possibly a bug.)
Hope this helps,
Jonathon
Hi,
I was wondering, I know standard Makefiles have a way of specifying
flags for a given file before the target / rule is defined
such as
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
is this possible in scons? or is the only way to pass in custom env
variables per target is when the target is defined?
https://www.scons.org/doc/latest/HTML/scons-user/ch03s09.html
such as
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
Also the way the docs read I think it doesn't make it clear if your
appending or replacing values in the environment variable (e.g. CFLAGS) for
that specific target (I'm assuming replacing)
I've been trying to see if I could port the Makefiles from micropython
across to scons btw, but as an initial step I've been trying to keep the
logic the same without changing the order of things too much
Many Thanks
Richard
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Jonathon Reinhart
2018-09-06 04:11:31 UTC
Permalink
Thanks Bill,

You're right, using the CFLAGS="$CFLAGS -Os" substitution is simpler.
I sometimes forget how well this works in SCons, and get worried about
bash-isms regarding spaces, etc.

I could have sworn that env.Override() was in the man page, but it
looks like I was wrong. We've been trying to reduce the number of
Clone()s in a large codebase (specifically in some custom
pseudo-builders) and I've successfully used env.Override() for this
purpose. Given that there are tests for it (in EnvironmentTests.py),
it seemed unlikely to go away.

Jonathon
Post by Bill Deegan
Don't use something which is not in the manpage.
It can be dropped without warning.
If you're going to use the modified CFLAGS as below many times
Then using Clone() is reasonable.
env=Environment(tools=[], MY_FLAG='ABC DEF')
env2=env.Clone(MY_FLAG="$MY_FLAG XYZ PQR")
print env['MY_FLAG']
print env2['MY_FLAG']
scons: Reading SConscript files ...
ABC DEF
ABC DEF XYZ PQR
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
(Jonathon Reinhart this is a bit simpler than the method you're recommending)
Should do the trick.
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start seeing memory and speed impacted.
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
https://github.com/SCons/scons-contrib
-Bill
SCons Project Co-Manager
Thanks for the info
I was wondering if there might have been a per target / file thing like with Require()
I think I'll use the Override example you've given above to use an OverrideEnvironment()
that seems to be the best way
this seems to work
env2 = env.Override(
{'CFLAGS': env.get('CFLAGS', []) + ['-Os']}
)
I think the Override method isn't documented in the user manual / man page list of functions from the looks of things.
For info I started writing a script to convert Makefiles to scons scripts
it's still very crude at this stage, and mostly tries to capture variable assignments and if blocks (not so much the rules) just to try and take out the majority of the leg work, still someone might find it usefull
https://github.com/grbd/Scons.Make2Scons
Many Thanks
Richard
Post by Jonathon Reinhart
Hi Richard,
You're correct that this syntax will override the variable (via an
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
env.Program('hello', 'hello.c', CFLAGS+=['-Os'])
env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
Alternatively, you can clone the environment to customize it for a set
foo_env = env.Clone()
foo_env.Append(CFLAGS=['-Os'])
foo_env.Program('hello', 'hello.c')
Do note that Clone() is expensive, and should be avoided in my
opinion. If you're not doing anything too crazy, you can get by with
envo = env.Override(
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
envo.Program('hello', 'hello.c')
Note: Don't try to Append() to an OverrideEnvironment; that call is
proxied to the underlying environment which would then be modified.
(This is possibly a bug.)
Hope this helps,
Jonathon
Hi,
I was wondering, I know standard Makefiles have a way of specifying flags for a given file before the target / rule is defined
such as
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
is this possible in scons? or is the only way to pass in custom env variables per target is when the target is defined?
https://www.scons.org/doc/latest/HTML/scons-user/ch03s09.html
such as
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
Also the way the docs read I think it doesn't make it clear if your appending or replacing values in the environment variable (e.g. CFLAGS) for that specific target (I'm assuming replacing)
I've been trying to see if I could port the Makefiles from micropython across to scons btw, but as an initial step I've been trying to keep the logic the same without changing the order of things too much
Many Thanks
Richard
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Bill Deegan
2018-09-06 04:17:20 UTC
Permalink
If it's not in the users guide or manpage it's not subject to deprecation
cycle..
(Those are the definitive spec for the user facing API for SCons. Thus the
checklist item on pull requests for docs and tests (and src/CHANGES.txt
modifications))

Why so many clones? Are the environment's being modified?
Are you seeing that the # of clones is actually causing you issues?
Are you Clone'ing as a form of write protection on the original env?
How many objects does "--debug=count" output for your build?

-Bill


On Thu, Sep 6, 2018 at 12:11 AM Jonathon Reinhart <
Post by Jonathon Reinhart
Thanks Bill,
You're right, using the CFLAGS="$CFLAGS -Os" substitution is simpler.
I sometimes forget how well this works in SCons, and get worried about
bash-isms regarding spaces, etc.
I could have sworn that env.Override() was in the man page, but it
looks like I was wrong. We've been trying to reduce the number of
Clone()s in a large codebase (specifically in some custom
pseudo-builders) and I've successfully used env.Override() for this
purpose. Given that there are tests for it (in EnvironmentTests.py),
it seemed unlikely to go away.
Jonathon
Post by Bill Deegan
Don't use something which is not in the manpage.
It can be dropped without warning.
If you're going to use the modified CFLAGS as below many times
Then using Clone() is reasonable.
env=Environment(tools=[], MY_FLAG='ABC DEF')
env2=env.Clone(MY_FLAG="$MY_FLAG XYZ PQR")
print env['MY_FLAG']
print env2['MY_FLAG']
scons: Reading SConscript files ...
ABC DEF
ABC DEF XYZ PQR
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
(Jonathon Reinhart this is a bit simpler than the method you're
recommending)
Post by Bill Deegan
Should do the trick.
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start
seeing memory and speed impacted.
Post by Bill Deegan
If you need to modify a flag, only for a single target, or a handful,
and especially in your case where you want to programmatically convert a
Post by Bill Deegan
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
https://github.com/SCons/scons-contrib
-Bill
SCons Project Co-Manager
Thanks for the info
I was wondering if there might have been a per target / file thing like
with Require()
Post by Bill Deegan
I think I'll use the Override example you've given above to use an
OverrideEnvironment()
Post by Bill Deegan
that seems to be the best way
this seems to work
env2 = env.Override(
{'CFLAGS': env.get('CFLAGS', []) + ['-Os']}
)
I think the Override method isn't documented in the user manual / man
page list of functions from the looks of things.
Post by Bill Deegan
For info I started writing a script to convert Makefiles to scons
scripts
Post by Bill Deegan
it's still very crude at this stage, and mostly tries to capture
variable assignments and if blocks (not so much the rules) just to try and
take out the majority of the leg work, still someone might find it usefull
Post by Bill Deegan
https://github.com/grbd/Scons.Make2Scons
Many Thanks
Richard
On Thu, 6 Sep 2018 at 01:09, Jonathon Reinhart <
Post by Jonathon Reinhart
Hi Richard,
You're correct that this syntax will override the variable (via an
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
I wish something like this would exist, but it's not valid Python
env.Program('hello', 'hello.c', CFLAGS+=['-Os'])
env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
Alternatively, you can clone the environment to customize it for a set
foo_env = env.Clone()
foo_env.Append(CFLAGS=['-Os'])
foo_env.Program('hello', 'hello.c')
Do note that Clone() is expensive, and should be avoided in my
opinion. If you're not doing anything too crazy, you can get by with
envo = env.Override(
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
envo.Program('hello', 'hello.c')
Note: Don't try to Append() to an OverrideEnvironment; that call is
proxied to the underlying environment which would then be modified.
(This is possibly a bug.)
Hope this helps,
Jonathon
On Wed, Sep 5, 2018 at 7:50 PM RW via Scons-users <
Hi,
I was wondering, I know standard Makefiles have a way of specifying
flags for a given file before the target / rule is defined
Post by Bill Deegan
Post by Jonathon Reinhart
such as
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
is this possible in scons? or is the only way to pass in custom env
variables per target is when the target is defined?
Post by Bill Deegan
Post by Jonathon Reinhart
https://www.scons.org/doc/latest/HTML/scons-user/ch03s09.html
such as
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
Also the way the docs read I think it doesn't make it clear if your
appending or replacing values in the environment variable (e.g. CFLAGS) for
that specific target (I'm assuming replacing)
Post by Bill Deegan
Post by Jonathon Reinhart
I've been trying to see if I could port the Makefiles from
micropython across to scons btw, but as an initial step I've been trying to
keep the logic the same without changing the order of things too much
Post by Bill Deegan
Post by Jonathon Reinhart
Many Thanks
Richard
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Gary Oberbrunner
2018-09-06 11:05:14 UTC
Permalink
Another approach to this is to add something like $EXTRA_CFLAGS to CFLAGS,
then you can just do
env.Program('hello', 'hello.c', EXTRA_CFLAGS=['-Os'])

-- Gary
Hi Bill,
Thanks for the info
As a seperate question I'm wondering if I should try to add Override() to
the user docs, or if it's classed as a non public API which might change
later on
I dont think it's depreciated looking at the code
it looks like the Builder.py uses it to actually do it's overrides under
the hood
and the Override() call is just a wrapper around the OverrideEnvironment
class
Many Thanks
Richard
Post by Bill Deegan
If it's not in the users guide or manpage it's not subject to deprecation
cycle..
(Those are the definitive spec for the user facing API for SCons. Thus
the checklist item on pull requests for docs and tests (and src/CHANGES.txt
modifications))
Why so many clones? Are the environment's being modified?
Are you seeing that the # of clones is actually causing you issues?
Are you Clone'ing as a form of write protection on the original env?
How many objects does "--debug=count" output for your build?
-Bill
On Thu, Sep 6, 2018 at 12:11 AM Jonathon Reinhart <
Post by Jonathon Reinhart
Thanks Bill,
You're right, using the CFLAGS="$CFLAGS -Os" substitution is simpler.
I sometimes forget how well this works in SCons, and get worried about
bash-isms regarding spaces, etc.
I could have sworn that env.Override() was in the man page, but it
looks like I was wrong. We've been trying to reduce the number of
Clone()s in a large codebase (specifically in some custom
pseudo-builders) and I've successfully used env.Override() for this
purpose. Given that there are tests for it (in EnvironmentTests.py),
it seemed unlikely to go away.
Jonathon
Post by Bill Deegan
Don't use something which is not in the manpage.
It can be dropped without warning.
If you're going to use the modified CFLAGS as below many times
Then using Clone() is reasonable.
env=Environment(tools=[], MY_FLAG='ABC DEF')
env2=env.Clone(MY_FLAG="$MY_FLAG XYZ PQR")
print env['MY_FLAG']
print env2['MY_FLAG']
scons: Reading SConscript files ...
ABC DEF
ABC DEF XYZ PQR
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
(Jonathon Reinhart this is a bit simpler than the method you're
recommending)
Post by Bill Deegan
Should do the trick.
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start
seeing memory and speed impacted.
Post by Bill Deegan
If you need to modify a flag, only for a single target, or a handful,
and especially in your case where you want to programmatically convert a
Post by Bill Deegan
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
https://github.com/SCons/scons-contrib
-Bill
SCons Project Co-Manager
On Wed, Sep 5, 2018 at 8:41 PM RW via Scons-users <
Thanks for the info
I was wondering if there might have been a per target / file thing
like with Require()
Post by Bill Deegan
I think I'll use the Override example you've given above to use an
OverrideEnvironment()
Post by Bill Deegan
that seems to be the best way
this seems to work
env2 = env.Override(
{'CFLAGS': env.get('CFLAGS', []) + ['-Os']}
)
I think the Override method isn't documented in the user manual / man
page list of functions from the looks of things.
Post by Bill Deegan
For info I started writing a script to convert Makefiles to scons
scripts
Post by Bill Deegan
it's still very crude at this stage, and mostly tries to capture
variable assignments and if blocks (not so much the rules) just to try and
take out the majority of the leg work, still someone might find it usefull
Post by Bill Deegan
https://github.com/grbd/Scons.Make2Scons
Many Thanks
Richard
On Thu, 6 Sep 2018 at 01:09, Jonathon Reinhart <
Post by Jonathon Reinhart
Hi Richard,
You're correct that this syntax will override the variable (via an
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
I wish something like this would exist, but it's not valid Python
env.Program('hello', 'hello.c', CFLAGS+=['-Os'])
env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
Alternatively, you can clone the environment to customize it for a
set
Post by Bill Deegan
Post by Jonathon Reinhart
foo_env = env.Clone()
foo_env.Append(CFLAGS=['-Os'])
foo_env.Program('hello', 'hello.c')
Do note that Clone() is expensive, and should be avoided in my
opinion. If you're not doing anything too crazy, you can get by with
envo = env.Override(
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
envo.Program('hello', 'hello.c')
Note: Don't try to Append() to an OverrideEnvironment; that call is
proxied to the underlying environment which would then be modified.
(This is possibly a bug.)
Hope this helps,
Jonathon
On Wed, Sep 5, 2018 at 7:50 PM RW via Scons-users <
Hi,
I was wondering, I know standard Makefiles have a way of
specifying flags for a given file before the target / rule is defined
Post by Bill Deegan
Post by Jonathon Reinhart
such as
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
is this possible in scons? or is the only way to pass in custom
env variables per target is when the target is defined?
Post by Bill Deegan
Post by Jonathon Reinhart
https://www.scons.org/doc/latest/HTML/scons-user/ch03s09.html
such as
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
Also the way the docs read I think it doesn't make it clear if
your appending or replacing values in the environment variable (e.g.
CFLAGS) for that specific target (I'm assuming replacing)
Post by Bill Deegan
Post by Jonathon Reinhart
I've been trying to see if I could port the Makefiles from
micropython across to scons btw, but as an initial step I've been trying to
keep the logic the same without changing the order of things too much
Post by Bill Deegan
Post by Jonathon Reinhart
Many Thanks
Richard
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
--
Gary
Bill Deegan
2018-09-06 15:46:45 UTC
Permalink
I think not.
Override() should stay internal API only.
There are supported ways to create override environments.

Once again, unless you are creating large # of Environment's via Clone(),
it's unlikely this is really a performance issue.

That said a lighter weight copy on write and/or read-only Clone could be a
useful addition.

-Bill
Hi Bill,
Thanks for the info
As a seperate question I'm wondering if I should try to add Override() to
the user docs, or if it's classed as a non public API which might change
later on
I dont think it's depreciated looking at the code
it looks like the Builder.py uses it to actually do it's overrides under
the hood
and the Override() call is just a wrapper around the OverrideEnvironment
class
Many Thanks
Richard
Post by Bill Deegan
If it's not in the users guide or manpage it's not subject to deprecation
cycle..
(Those are the definitive spec for the user facing API for SCons. Thus
the checklist item on pull requests for docs and tests (and src/CHANGES.txt
modifications))
Why so many clones? Are the environment's being modified?
Are you seeing that the # of clones is actually causing you issues?
Are you Clone'ing as a form of write protection on the original env?
How many objects does "--debug=count" output for your build?
-Bill
On Thu, Sep 6, 2018 at 12:11 AM Jonathon Reinhart <
Post by Jonathon Reinhart
Thanks Bill,
You're right, using the CFLAGS="$CFLAGS -Os" substitution is simpler.
I sometimes forget how well this works in SCons, and get worried about
bash-isms regarding spaces, etc.
I could have sworn that env.Override() was in the man page, but it
looks like I was wrong. We've been trying to reduce the number of
Clone()s in a large codebase (specifically in some custom
pseudo-builders) and I've successfully used env.Override() for this
purpose. Given that there are tests for it (in EnvironmentTests.py),
it seemed unlikely to go away.
Jonathon
Post by Bill Deegan
Don't use something which is not in the manpage.
It can be dropped without warning.
If you're going to use the modified CFLAGS as below many times
Then using Clone() is reasonable.
env=Environment(tools=[], MY_FLAG='ABC DEF')
env2=env.Clone(MY_FLAG="$MY_FLAG XYZ PQR")
print env['MY_FLAG']
print env2['MY_FLAG']
scons: Reading SConscript files ...
ABC DEF
ABC DEF XYZ PQR
scons: done reading SConscript files.
scons: Building targets ...
scons: `.' is up to date.
scons: done building targets.
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
(Jonathon Reinhart this is a bit simpler than the method you're
recommending)
Post by Bill Deegan
Should do the trick.
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start
seeing memory and speed impacted.
Post by Bill Deegan
If you need to modify a flag, only for a single target, or a handful,
and especially in your case where you want to programmatically convert a
Post by Bill Deegan
env.Program('target',[ sources ], CFLAG="$CFLAG -Os")
https://github.com/SCons/scons-contrib
-Bill
SCons Project Co-Manager
On Wed, Sep 5, 2018 at 8:41 PM RW via Scons-users <
Thanks for the info
I was wondering if there might have been a per target / file thing
like with Require()
Post by Bill Deegan
I think I'll use the Override example you've given above to use an
OverrideEnvironment()
Post by Bill Deegan
that seems to be the best way
this seems to work
env2 = env.Override(
{'CFLAGS': env.get('CFLAGS', []) + ['-Os']}
)
I think the Override method isn't documented in the user manual / man
page list of functions from the looks of things.
Post by Bill Deegan
For info I started writing a script to convert Makefiles to scons
scripts
Post by Bill Deegan
it's still very crude at this stage, and mostly tries to capture
variable assignments and if blocks (not so much the rules) just to try and
take out the majority of the leg work, still someone might find it usefull
Post by Bill Deegan
https://github.com/grbd/Scons.Make2Scons
Many Thanks
Richard
On Thu, 6 Sep 2018 at 01:09, Jonathon Reinhart <
Post by Jonathon Reinhart
Hi Richard,
You're correct that this syntax will override the variable (via an
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
I wish something like this would exist, but it's not valid Python
env.Program('hello', 'hello.c', CFLAGS+=['-Os'])
env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
Alternatively, you can clone the environment to customize it for a
set
Post by Bill Deegan
Post by Jonathon Reinhart
foo_env = env.Clone()
foo_env.Append(CFLAGS=['-Os'])
foo_env.Program('hello', 'hello.c')
Do note that Clone() is expensive, and should be avoided in my
opinion. If you're not doing anything too crazy, you can get by with
envo = env.Override(
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
envo.Program('hello', 'hello.c')
Note: Don't try to Append() to an OverrideEnvironment; that call is
proxied to the underlying environment which would then be modified.
(This is possibly a bug.)
Hope this helps,
Jonathon
On Wed, Sep 5, 2018 at 7:50 PM RW via Scons-users <
Hi,
I was wondering, I know standard Makefiles have a way of
specifying flags for a given file before the target / rule is defined
Post by Bill Deegan
Post by Jonathon Reinhart
such as
$(PY_BUILD)/nlr%.o: CFLAGS += -Os
is this possible in scons? or is the only way to pass in custom
env variables per target is when the target is defined?
Post by Bill Deegan
Post by Jonathon Reinhart
https://www.scons.org/doc/latest/HTML/scons-user/ch03s09.html
such as
env.Program('hello', 'hello.c', CFLAGS=['-Os'])
Also the way the docs read I think it doesn't make it clear if
your appending or replacing values in the environment variable (e.g.
CFLAGS) for that specific target (I'm assuming replacing)
Post by Bill Deegan
Post by Jonathon Reinhart
I've been trying to see if I could port the Makefiles from
micropython across to scons btw, but as an initial step I've been trying to
keep the logic the same without changing the order of things too much
Post by Bill Deegan
Post by Jonathon Reinhart
Many Thanks
Richard
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Jonathon Reinhart
2018-09-06 16:30:07 UTC
Permalink
Hi Bill,
Post by Bill Deegan
Why so many clones? Are the environment's being modified?
Sometimes we clone out of safety (see blow), and sometimes we clone
out of necessity.

In the case of Pseudo-builders, we had some (arguably poorly-written)
that would first Clone the environment, and then make target-specific
modifications to it. These would be better off as overrides when
calling lower-level builders (e.g. env.Object). But sometimes the
changes apply to multiple sub-builders, so it made more sense to
modify the environment. Hence the reason that oenv = env.Override()
works so well here.
Post by Bill Deegan
Are you seeing that the # of clones is actually causing you issues?
Hard to say. There's a pretty long delay before SCons starts building,
and we're continuously seeking to improve that.
Post by Bill Deegan
Are you Clone'ing as a form of write protection on the original env?
Yes, we tend to follow this pattern for safety:

env.SConscript(
dirs = 'somechild',
variant_dir = '$BUILD_DIR/somechild',
duplicate = False,
exports = dict(env = env.Clone()),
)
Post by Bill Deegan
How many objects does "--debug=count" output for your build?
Object counts:
pre- post- pre- post-
read read build build Class
0 1745 1745 32256 Action.CommandAction
0 53 53 53 Action.CommandGeneratorAction
0 185 185 185 Action.FunctionAction
0 117 117 117 Action.LazyAction
0 107 107 107 Action.ListAction
0 1505 1505 1505 Builder.BuilderBase
0 43 43 43 Builder.CompositeBuilder
0 6343 6343 6343 Builder.OverrideWarner
0 7 7 7 Environment.Base
0 2177 2177 2177 Environment.EnvironmentClone
0 1666 1666 17571 Environment.OverrideEnvironment
0 17869 17869 18825 Executor.Executor
0 8 8 12220 Executor.Null
0 29711 29711 32204 Node.FS.Base
0 4254 4254 5100 Node.FS.Dir
0 12621 12621 13353 Node.FS.File
0 29843 29843 32336 Node.Node
Post by Bill Deegan
There are supported ways to create override environments.
Not ones that you can have a reference to, for the purpose of calling
multiple builders upon.
Post by Bill Deegan
Once again, unless you are creating large # of Environment's via Clone(), it's unlikely this is really a performance issue.
I have a colleague that once tested this. Sorry I don't have access to
the code right now, but it basically created about 1000 clones. I do
have these numbers we noted:

Full build:
Without clone: 1m 9s
With clone: 2m 11s

With -n (dry-run) and >/dev/null:
Without clone: 14.1s
With clone: 17.5s (+3.4s)

Only invoking SConscript: no actual building
Without clone: 2.3s
With clone: 4.7s (+2.4s)

No Sonscript invocation:
Without clone: 0.4s
With clone: 2.6s (+2.2s)

With SConscript call but without env.Program() call (not actually
building anything):
env = OverrideEnvironment(local_env); env.Append(COUNTER=counter): 2.05s *
env.Clone(COUNTER=counter):
4.80s (+2.75s)

[*] I realize that this test was wrong -- you can't Append() to an
OverrideEnvironment without modifying the original env.
Post by Bill Deegan
That said a lighter weight copy on write and/or read-only Clone could be a useful addition.
I agree. Being able to simply call one efficient API would be ideal.
Bill Deegan
2018-09-06 16:48:29 UTC
Permalink
Can you pastebin some example pseudo builders?
Likely there's other ways to do what you want which are faster/lighter
weight.

Also, explicitly specify only the tools you need
env = Environment(tools=[my list of tools])
DefaultEnvironment(tools=[])
Can reduce startup time a bit.

-Bill

On Thu, Sep 6, 2018 at 12:30 PM Jonathon Reinhart <
Hi Bill,
Post by Bill Deegan
Why so many clones? Are the environment's being modified?
Sometimes we clone out of safety (see blow), and sometimes we clone
out of necessity.
In the case of Pseudo-builders, we had some (arguably poorly-written)
that would first Clone the environment, and then make target-specific
modifications to it. These would be better off as overrides when
calling lower-level builders (e.g. env.Object). But sometimes the
changes apply to multiple sub-builders, so it made more sense to
modify the environment. Hence the reason that oenv = env.Override()
works so well here.
Post by Bill Deegan
Are you seeing that the # of clones is actually causing you issues?
Hard to say. There's a pretty long delay before SCons starts building,
and we're continuously seeking to improve that.
Post by Bill Deegan
Are you Clone'ing as a form of write protection on the original env?
env.SConscript(
dirs = 'somechild',
variant_dir = '$BUILD_DIR/somechild',
duplicate = False,
exports = dict(env = env.Clone()),
)
Post by Bill Deegan
How many objects does "--debug=count" output for your build?
pre- post- pre- post-
read read build build Class
0 1745 1745 32256 Action.CommandAction
0 53 53 53 Action.CommandGeneratorAction
0 185 185 185 Action.FunctionAction
0 117 117 117 Action.LazyAction
0 107 107 107 Action.ListAction
0 1505 1505 1505 Builder.BuilderBase
0 43 43 43 Builder.CompositeBuilder
0 6343 6343 6343 Builder.OverrideWarner
0 7 7 7 Environment.Base
0 2177 2177 2177 Environment.EnvironmentClone
0 1666 1666 17571 Environment.OverrideEnvironment
0 17869 17869 18825 Executor.Executor
0 8 8 12220 Executor.Null
0 29711 29711 32204 Node.FS.Base
0 4254 4254 5100 Node.FS.Dir
0 12621 12621 13353 Node.FS.File
0 29843 29843 32336 Node.Node
Post by Bill Deegan
There are supported ways to create override environments.
Not ones that you can have a reference to, for the purpose of calling
multiple builders upon.
Post by Bill Deegan
Once again, unless you are creating large # of Environment's via
Clone(), it's unlikely this is really a performance issue.
I have a colleague that once tested this. Sorry I don't have access to
the code right now, but it basically created about 1000 clones. I do
Without clone: 1m 9s
With clone: 2m 11s
Without clone: 14.1s
With clone: 17.5s (+3.4s)
Only invoking SConscript: no actual building
Without clone: 2.3s
With clone: 4.7s (+2.4s)
Without clone: 0.4s
With clone: 2.6s (+2.2s)
With SConscript call but without env.Program() call (not actually
2.05s *
4.80s (+2.75s)
[*] I realize that this test was wrong -- you can't Append() to an
OverrideEnvironment without modifying the original env.
Post by Bill Deegan
That said a lighter weight copy on write and/or read-only Clone could be
a useful addition.
I agree. Being able to simply call one efficient API would be ideal.
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Petteri Hintsanen
2018-09-10 12:39:45 UTC
Permalink
Post by Bill Deegan
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start seeing
memory and speed impacted.
This is news to me. I have always thought that cloning is relatively
cheap.

We use simple wrappers around standard SCons functions Library and
Program to simplify dependency handling, mostly for linking against
static libraries and importing packages via pkg-config. Greatly
simplified, it looks something like this:

link_envs = []

def build_bin(env, target, sources, libs, pkgs):
# Import packages
if pkgs:
env = env.Clone()
# use pkg-config to bring CFLAGS into env
# and append pkg-config --libs into libs
import_pkgs(env, pkgs, libs)

# Compile
objs = env.StaticObject(sources)

# Link
link_env = env
if libs:
link_env = env.Clone()
link_envs.append([link_env, libs])

program = link_env.Program(target, objs)

link_envs contain all (cloned) environments that have link-time
dependencies. They are augmented by link_env.Append(LIBS = ...)
after all SConscripts have been read, so that programs will be linked
against libraries they depend on. [To do that we use a dictionary
which maps between strings and Library nodes (we refer to libraries
by their names, ie. strings).]

This is done after all SConscritps have been read because that way we
do not need to worry about the evaluation order of various
SConscripts which define the said libraries. Nor do we need to
Export("mylib") in SConscript that builds "mylib" or Import("mylib")
in SConscripts that refer to "mylib".

But in this scheme we clone a lot. Maybe this is too heavyweight?

Regards,
Petteri
Hua Yanghao
2018-09-10 14:40:34 UTC
Permalink
Not sure how Object(CFLAGS = old + new) is handled, but I have
verified that definitely going to customize for each and every object,
and no clash seen.
If this, behind the scene is also using a Clone() somehow I starts to
understand why my build startup is a bit slow (totally acceptable
though, e.g. for a build that creates 22 different target, a few
hundred C files each), around 9 seconds before the first build prints
on screen.
Post by Petteri Hintsanen
Post by Bill Deegan
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start seeing
memory and speed impacted.
This is news to me. I have always thought that cloning is relatively
cheap.
We use simple wrappers around standard SCons functions Library and
Program to simplify dependency handling, mostly for linking against
static libraries and importing packages via pkg-config. Greatly
link_envs = []
# Import packages
env = env.Clone()
# use pkg-config to bring CFLAGS into env
# and append pkg-config --libs into libs
import_pkgs(env, pkgs, libs)
# Compile
objs = env.StaticObject(sources)
# Link
link_env = env
link_env = env.Clone()
link_envs.append([link_env, libs])
program = link_env.Program(target, objs)
link_envs contain all (cloned) environments that have link-time
dependencies. They are augmented by link_env.Append(LIBS = ...)
after all SConscripts have been read, so that programs will be linked
against libraries they depend on. [To do that we use a dictionary
which maps between strings and Library nodes (we refer to libraries
by their names, ie. strings).]
This is done after all SConscritps have been read because that way we
do not need to worry about the evaluation order of various
SConscripts which define the said libraries. Nor do we need to
Export("mylib") in SConscript that builds "mylib" or Import("mylib")
in SConscripts that refer to "mylib".
But in this scheme we clone a lot. Maybe this is too heavyweight?
Regards,
Petteri
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Mats Wichmann
2018-09-10 15:53:58 UTC
Permalink
Post by Hua Yanghao
Not sure how Object(CFLAGS = old + new) is handled, but I have
verified that definitely going to customize for each and every object,
and no clash seen.
If this, behind the scene is also using a Clone() somehow I starts to
understand why my build startup is a bit slow (totally acceptable
though, e.g. for a build that creates 22 different target, a few
hundred C files each), around 9 seconds before the first build prints
on screen.
I've looked at the work done to clone, and it's a fair bit. I've got a
project that does a lot of clones, and is slow to start up, but I'm far
from convinced it's the cost of cloning that makes it so. I'd suggest
if startup time isn't bugging you, don't worry about it. If startup
time *is* bugging you, then clones are _one_ place to look.
Post by Hua Yanghao
Post by Petteri Hintsanen
Post by Bill Deegan
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start seeing
memory and speed impacted.
...
Post by Hua Yanghao
Post by Petteri Hintsanen
But in this scheme we clone a lot. Maybe this is too heavyweight?
Regards,
Petteri
Bill Deegan
2018-09-11 20:35:16 UTC
Permalink
use --debug=count to help you know how many Environment()'s you're creating
(including via clone).
If the number is large and you're having performance problems, then it's
likely something worth looking at.
(large >1000 or maybe 10k).

-Bill
Post by Mats Wichmann
Post by Hua Yanghao
Not sure how Object(CFLAGS = old + new) is handled, but I have
verified that definitely going to customize for each and every object,
and no clash seen.
If this, behind the scene is also using a Clone() somehow I starts to
understand why my build startup is a bit slow (totally acceptable
though, e.g. for a build that creates 22 different target, a few
hundred C files each), around 9 seconds before the first build prints
on screen.
I've looked at the work done to clone, and it's a fair bit. I've got a
project that does a lot of clones, and is slow to start up, but I'm far
from convinced it's the cost of cloning that makes it so. I'd suggest
if startup time isn't bugging you, don't worry about it. If startup
time *is* bugging you, then clones are _one_ place to look.
Post by Hua Yanghao
Post by Petteri Hintsanen
Post by Bill Deegan
Here's the caveat.
Don't make a gazillion Clone's they're not lightweight.
If you make 100, it won't kill you, if you make 1000's you may start
seeing
Post by Hua Yanghao
Post by Petteri Hintsanen
Post by Bill Deegan
memory and speed impacted.
...
Post by Hua Yanghao
Post by Petteri Hintsanen
But in this scheme we clone a lot. Maybe this is too heavyweight?
Regards,
Petteri
_______________________________________________
Scons-users mailing list
https://pairlist4.pair.net/mailman/listinfo/scons-users
Hua Yanghao
2018-09-06 20:29:44 UTC
Permalink
On Thu, Sep 6, 2018 at 2:09 AM Jonathon Reinhart
Post by Jonathon Reinhart
env.Program('hello', 'hello.c',
CFLAGS = env.get('CFLAGS', []) + ['-Os'],
)
This can even be applied to a per-object basis already, this is what I do:
obj1 = Object(f, CFLAGS = old_cflags + flags1)
...
objN = Object(f, CFLAGS = old_cflags + flagsN)

This way you can customize for each different object a different set
of compilation flags.
Loading...