[Scons-users] Generating header from cpp file causes cycle

Jean-Baptiste Lab jeanbaptiste.lab at gmail.com
Mon Mar 20 04:50:34 EDT 2017


> And the header is not needed by the cpp file (it has no dependencies)

But it sure looks like this CPP file #includes that header...

I think your Makefile example is missing a piece of the puzzle that
SCons possess: SCons figures out that this CPP file includes the
generated header, make doesn't (unless you first run a GCC pass to
generate the entire dependency tree, which your example Makefile doesn't
do AFAICT). Basically, your Makefile is missing this dependency:

test.cpp: test.h

Is this really the scenario that you are trying to implement: "test.h"
is generated from "test.cpp" AND "test.cpp" includes "test.h" ?

On 2017-03-20 02:10, Ivan Nedrehagen via Scons-users wrote:
>
> It must be me who is misunderstanding something, I have generated a
> make file to test your assumptions,
>
> and I cannot see the behaviour that you describe.
>
> Make behaves like I want to:
>
> CPP = g++
> PY = python
> GENERATOR = gen.py
> CPPFLAGS = -I.
> DEPS = test.h
> OBJS = test.o
>
> test.h: test.cpp
>     $(PY) $(GENERATOR) $@ $^
>
> test.o: test.cpp test.h
>     $(CPP) -c -o $@ $< $(CPPFLAGS)
>
> testexe: test.o
>     $(CPP) -o $@ $^ $(CPPFLAGS)
>
> With this make file, I get this behaviour:
>
> $ make testexe
>
> python gen.py test.h test.cpp
> generating test.h from test.cpp
> g++ -c -o test.o test.cpp -I.
> g++ -o testexe test.o -I.
>
> $ touch test.cpp
> $ make testexe
>
> python gen.py test.h test.cpp
> generating test.h from test.cpp
> g++ -c -o test.o test.cpp -I.
> g++ -o testexe test.o -I.
>
> $ touch test.h
> $ make testexe
>
> g++ -c -o test.o test.cpp -I.
> g++ -o testexe test.o -I.
>
> $ touch test.o
> $ make testexe
>
> g++ -o testexe test.o -I.
>
> $ touch test.cpp
> $ make testexe
>
> python gen.py test.h test.cpp
> generating test.h from test.cpp
> g++ -c -o test.o test.cpp -I.
> g++ -o testexe test.o -I.
>
> The above is the behaviour I would like. Perhaps I am expressing it
> the wrong way in SCons.
>
>
> You say that if I generate a file which is used in any way in
> generating the file I got a cycle.
>
> But the cpp file is used in generating, not the header
>
> And the header is not needed by the cpp file (it has no depedencies)
>
> If even if this was the case the SCons would say:
>
> test.h -> test.cpp -> test.h
>
> when reporting the cycle
>
>
> My actual code generator works like this:
>
> c++ headers is largely redundant. Most of the information can be found
> in the cpp file.
>
> For my unittest framework, all information needed are in the cpp file.
>
> The generator takes the cpp file, and generate a simple header from it.
>
>
> On 2017-03-19 16:30, Bill Deegan wrote:
>> If you generate a file which is used in any way in generating the
>> file, then you have a dependency cycle.
>>
>> SCons will scan the sources and find these.
>> If you did this with make it would always rebuild your code generator.
>>
>> What does your actual code generator do with the header file it
>> includes which it generates?
>>
>> Is this a version string?
>>
>> -Bill
>>
>> On Sun, Mar 19, 2017 at 6:07 AM, Jean-Baptiste Lab
>> <jeanbaptiste.lab at gmail.com <mailto:jeanbaptiste.lab at gmail.com>> wrote:
>>
>>     I think what is happening behind the scene is that SCons will
>>     constantly update the dependencies as it discovers them, to get
>>     the most accurate information possible.
>>
>>     So you are right, when first processing the dependencies for
>>     "test", there are no trace of "test.h".
>>     But SCons knows already that test depends on test.o which depends
>>     on test.cpp (those are *explicit* dependencies).
>>     Later on with the Header builder, you add (manually in a sense)
>>     to test.h a dependency on test.cpp,
>>     which will add the dependencies of test.cpp to test.h, hence
>>     test2.h showing up in test.h dependencies...
>>
>>     That's were the cycle comes from.
>>
>>     You might want to take a look at SCons's Ignore() functionality
>>     and see if you can use it for your use case...
>>
>>     Hope this helps,
>>
>>     JB
>>
>>     On 2017-03-19 10:55, Ivan Nedrehagen via Scons-users wrote:
>>>
>>>     Hi,
>>>
>>>     I have printed the tree where I have replaced the #include
>>>     "test.h" with "test2.h"
>>>
>>>     g++ -o test.o -c test.cpp
>>>     +-.
>>>       +-SConstruct
>>>       +-test
>>>       | +-test.o
>>>       | | +-test.cpp
>>>       | | +-test2.h
>>>       | | +-/usr/bin/g++
>>>       | +-/usr/bin/g++
>>>       +-test.cpp
>>>       +-test.h
>>>       | +-test.cpp
>>>       | +-test2.h
>>>       +-[test.o]
>>>       +-test2.h
>>>
>>>     Here you can see that test.cpp depends on nothing (it cannot, it
>>>     isn't built), however the test.o depends on test.cpp and test2.h
>>>     (which is correct)
>>>
>>>     But somehow the test.h has also got a dependency on test2.h
>>>
>>>     As I understand SCons, test.cpp should be scanned by the Header
>>>     builders scanner
>>>
>>>     It behave as if the header builder was a object builder with a
>>>     standard cpp scanner
>>>
>>>     So it must be my understanding of the scanners or SCons
>>>     dependencies that are wrong.
>>>
>>>     But there definitely doesn't have to be a cycle here.
>>>
>>>     If test.h changes test.o must be rebuilt
>>>
>>>     If test.cpp changes test.h and test.o must be rebuilt
>>>
>>>
>>>     On 2017-03-19 10:11, Jean-Baptiste Lab wrote:
>>>>     Hi,
>>>>
>>>>     SCons is doing the right thing here I believe...
>>>>
>>>>     > header = env.Header("test.h", "test.cpp")
>>>>
>>>>     This statements indicates that "test.h" depends on "test.cpp"
>>>>     (builders implicitly make their targets dependent on their
>>>>     sources).
>>>>
>>>>     Then using:
>>>>
>>>>     > exe = env.Program("test.cpp")
>>>>
>>>>     you indicate that the "exe" target depends on "test.cpp".
>>>>     "test.cpp" will be scanned by SCons for its dependencies, which
>>>>     will end up in eventually in "test.cpp" depends on "test.h".
>>>>     SCons then realizes that "Oh, I know how to build "test.h" and
>>>>     it depends on "test.cpp"" and that's where the dependency cycle
>>>>     occurs ("->" in the following indicates "depends on"):
>>>>
>>>>     exe -> test.o -> test.cpp -> test.h (through SCons scanner) ->
>>>>     test.cpp (through env.Header) -> test.h ->... -> test.h -> test.cpp
>>>>
>>>>     The scenario you describe is: cpp file X is needed to build the
>>>>     header Y that will be included in X which is correctly a
>>>>     circular dependency... SCons has no way of figuring out when to
>>>>     build what:
>>>>     - X has changed -> "I need to rebuild Y"
>>>>     - wait, Y has changed -> "I need to rebuild X"
>>>>     - wash, rinse, repeat
>>>>
>>>>     The usual way to solve this is to refactor the dependencies,
>>>>     maybe using "test.h.in <http://test.h.in>" file and use that as
>>>>     the source of you env.Header() builder...
>>>>
>>>>     Hope this helps,
>>>>
>>>>     JB
>>>>
>>>>
>>>>     On 2017-03-19 09:51, Ivan Nedrehagen via Scons-users wrote:
>>>>>
>>>>>     This is a case that reproduce the problem I have.
>>>>>
>>>>>
>>>>>     It is not perfect, but it still illustrates the problem.
>>>>>
>>>>>
>>>>>     the header I generate doesn't include anything. It becomes one
>>>>>     line: "class Test {};"
>>>>>
>>>>>     the test.cpp includes the file I generate of course. But in my
>>>>>     understanding that only means that test.o depends on test.cpp
>>>>>     and test.h
>>>>>
>>>>>     This is reflected in the tree.
>>>>>
>>>>>     For me it looks like that SCons decide that test.h depends on
>>>>>     test.cpp, and that I therefore also must depend on test.h
>>>>>     (since it is included)
>>>>>
>>>>>     This is also reflected in the tree (if I changed the #include
>>>>>     "test.h" in test.cpp into #include "test2.h", test.h seems to
>>>>>     be dependant on test2.h)
>>>>>
>>>>>
>>>>>     Please explain what I am doing wrong...
>>>>>
>>>>>
>>>>>     On 2017-03-19 05:17, Bill Deegan wrote:
>>>>>>     Your header file builder includes the header being generated.
>>>>>>     There is a dependency cycle..
>>>>>>     Is that really the code you have? (or just an example which
>>>>>>     doesn't mimic your actual build?)
>>>>>>
>>>>>>
>>>>>>     -Bill
>>>>>>
>>>>>>     On Sat, Mar 18, 2017 at 10:00 PM, Ivan Nedrehagen via
>>>>>>     Scons-users <scons-users at scons.org
>>>>>>     <mailto:scons-users at scons.org>> wrote:
>>>>>>
>>>>>>         I have a unit test library that generates headers from
>>>>>>         the cpp files that contains tests.
>>>>>>
>>>>>>         Lately with my updated version of SCons (2.5.0) I get
>>>>>>         dependency cycles.
>>>>>>
>>>>>>         (It is very hard to debug these cycles, because --tree
>>>>>>         doesn't output anything)
>>>>>>
>>>>>>
>>>>>>         A case that reproduce the problem:
>>>>>>
>>>>>>         --- SConstruct ---
>>>>>>
>>>>>>         def create_header(target, source, env):
>>>>>>             txt = " class Test {}; \n"
>>>>>>             file = open(str(target))
>>>>>>             file.write(txt)
>>>>>>
>>>>>>         env = Environment()
>>>>>>
>>>>>>         headerBuilder = env.Builder(action=create_header)
>>>>>>
>>>>>>         env.Append(BUILDERS={"Header": headerBuilder})
>>>>>>
>>>>>>         header = env.Header("test.h", "test.cpp")
>>>>>>         exe = env.Program("test.cpp")
>>>>>>
>>>>>>         --- test.cpp ---
>>>>>>
>>>>>>         #include "test.h"
>>>>>>
>>>>>>         int main() {
>>>>>>           Test test;
>>>>>>           return 0;
>>>>>>         }
>>>>>>
>>>>>>         --- Result ---
>>>>>>
>>>>>>         scons: *** Found dependency cycle(s):
>>>>>>           test.h -> test.h
>>>>>>
>>>>>>         --- End of Case ---
>>>>>>
>>>>>>         Why is this failing? I understand that the test.o should
>>>>>>         be dependent on test.h, but why is suddenly test.h
>>>>>>         depending on itself?
>>>>>>
>>>>>>         I tried to set target_scanner and source_scanner to None
>>>>>>         in the builder just to see if this made a difference, but no.
>>>>>>
>>>>>>         How can I express a builder that builds header files from
>>>>>>         cpp files without creating a builder that build
>>>>>>         dependency cycles?
>>>>>>
>>>>>>         _______________________________________________
>>>>>>         Scons-users mailing list
>>>>>>         Scons-users at scons.org <mailto:Scons-users at scons.org>
>>>>>>         https://pairlist4.pair.net/mailman/listinfo/scons-users
>>>>>>         <https://pairlist4.pair.net/mailman/listinfo/scons-users>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>>     _______________________________________________
>>>>>     Scons-users mailing list
>>>>>     Scons-users at scons.org <mailto:Scons-users at scons.org>
>>>>>     https://pairlist4.pair.net/mailman/listinfo/scons-users
>>>>>     <https://pairlist4.pair.net/mailman/listinfo/scons-users>
>>>>
>>>>     _______________________________________________
>>>>     Scons-users mailing list
>>>>     Scons-users at scons.org <mailto:Scons-users at scons.org>
>>>>     https://pairlist4.pair.net/mailman/listinfo/scons-users
>>>>     <https://pairlist4.pair.net/mailman/listinfo/scons-users>
>>>
>>>     _______________________________________________
>>>     Scons-users mailing list
>>>     Scons-users at scons.org <mailto:Scons-users at scons.org>
>>>     https://pairlist4.pair.net/mailman/listinfo/scons-users
>>>     <https://pairlist4.pair.net/mailman/listinfo/scons-users>
>>
>>     _______________________________________________ Scons-users
>>     mailing list Scons-users at scons.org <mailto:Scons-users at scons.org>
>>     https://pairlist4.pair.net/mailman/listinfo/scons-users
>>     <https://pairlist4.pair.net/mailman/listinfo/scons-users> 
>>
>> _______________________________________________
>> Scons-users mailing list
>> Scons-users at scons.org
>> https://pairlist4.pair.net/mailman/listinfo/scons-users
>
> _______________________________________________
> 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/20170320/09e9b0ce/attachment-0001.html>


More information about the Scons-users mailing list