[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