
Hi, I've inherited some code that currently compiles and runs under Linux (gcc 4.2.1) and am looking to switch to Windows using the vs 2003 with SP1. Unfortunately the code fails to compile with undefined symbols. An example of the code is as follows: #include <boost/statechart/event.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> #include <boost/statechart/transition.hpp> #include <iostream> namespace sc = boost::statechart; struct EvStartStop : sc::event< EvStartStop > {}; struct EvReset : sc::event< EvReset > {}; struct Active; struct Stopped; struct Running; struct StopWatch : sc::state_machine< StopWatch, Active > {}; struct Active : sc::simple_state< Active, StopWatch, Stopped > { typedef sc::transition< EvReset, Active > reactions; }; struct Stopped : sc::simple_state< Stopped, Active > { typedef sc::transition< EvStartStop, Running > reactions; }; int main() { return 0; } I'm aware that the code is incomplete as Running is only forward declared. It is provided this way since the real model under Linux is broken up across multiple headers rather than all being in one header. Under Linux the above code compiles without an issue but vs 2003 complains about Running being undefined. Removing sc::transition< EvStartStop, Running > makes the compilation problem disappear. A similiar issue exists for Windows if Running was defined but uses an inner state that was only foward declared. Again Linux seems to have no problems. For vs 2003 wrapping the reactions or inner state with mpl::list<> does not fix the problem. Can anyone suggest if what is being done here is broken under vs 2003, or should not be allowed under gcc? Are there workarounds for the boost headers for vs 2003 or recommendations to allow splitting the state machine across multiple headers? Best Regards, Simon

Hi Simon
I've inherited some code that currently compiles and runs under Linux (gcc 4.2.1) and am looking to switch to Windows using the vs 2003. Unfortunately the code fails to compile with undefined symbols. An example of the code is as follows: #include <boost/statechart/event.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> #include <boost/statechart/transition.hpp> #include <iostream> namespace sc = boost::statechart; struct EvStartStop : sc::event< EvStartStop > {}; struct EvReset : sc::event< EvReset > {}; struct Active; struct Stopped; struct Running; struct StopWatch : sc::state_machine< StopWatch, Active > {}; struct Active : sc::simple_state< Active, StopWatch, Stopped > { typedef sc::transition< EvReset, Active > reactions; }; struct Stopped : sc::simple_state< Stopped, Active > { typedef sc::transition< EvStartStop, Running > reactions; }; int main() { return 0; } I'm aware that the code is incomplete as Running is only forward declared. It is provided this way since the real model under Linux is broken up across multiple headers rather than all being in one header.
Ok, I guess this means that the whole machine is defined in one translation unit? If so, I don't see why you couldn't modify the include order, so that it compiles with VS2003 also?
Under Linux the above code compiles without an issue
Add the following to main() and it will no longer compile: StopWatch stopWatch; stopWatch.initiate(); This forces the instantiation of all code, including the transition to Running. So, gcc now should also complain about the missing definition for Running.
but vs 2003 complains about Running being undefined.
So does VS2008. Frankly, I'm not sure whether GCC is too lazy or VS too eager. But it shouldn't matter, if the whole machine is in one TU, you should be able to fix this by shuffling around includes (unless I'm missing something). HTH, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

Hi Andreas, Thankyou for your reply.
So does VS2008. Frankly, I'm not sure whether GCC is too lazy or VS too eager. But it shouldn't matter, if the whole machine is in one TU, you should be able to fix this by shuffling around includes (unless I'm missing something).
Ok. By TU I take that to be one cpp file with its includes. For maintenance reasons it appears the model was broken up into multiple cpp files. It seems the model was structured under gcc that every inner level is a new header that just includes its parent, but not any children (inners). The above reply is effectively saying to create one large header file with the whole model in it. I was just checking whether that was required or whether it was just a feature of vs2003, which it appears not to be from your comment. So just to confirm the expectation for the state machines is that effectively the whole definition is in one header file and there is no mechanism to divide it up short without effectively including all header files into every cpp file? Simon -----Original Message----- From: Andreas Huber <ahd6974-spamboostorgtrap@yahoo.com> To: boost@lists.boost.org Sent: Thu, Mar 11, 2010 9:40 pm Subject: Re: [boost] [statechart] Undefined type Hi Simon
I've inherited some code that currently compiles and runs under Linux (gcc 4.2.1) and am looking to switch to Windows using the vs 2003. Unfortunately the code fails to compile with undefined symbols. An example of the code is as follows: #include <boost/statechart/event.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> #include <boost/statechart/transition.hpp> #include <iostream> namespace sc = boost::statechart; struct EvStartStop : sc::event< EvStartStop > {}; struct EvReset : sc::event< EvReset > {}; struct Active; struct Stopped; struct Running; struct StopWatch : sc::state_machine< StopWatch, Active > {}; struct Active : sc::simple_state< Active, StopWatch, Stopped > { typedef sc::transition< EvReset, Active > reactions; }; struct Stopped : sc::simple_state< Stopped, Active > { typedef sc::transition< EvStartStop, Running > reactions; }; int main() { return 0; } I'm aware that the code is incomplete as Running is only forward declared. It is provided this way since the real model under Linux is broken up across multiple headers rather than all being in one header.
Ok, I guess this means that the whole machine is defined in one translation unit? If so, I don't see why you couldn't modify the include order, so that it compiles with VS2003 also?
Under Linux the above code compiles without an issue
Add the following to main() and it will no longer compile: StopWatch stopWatch; stopWatch.initiate(); This forces the instantiation of all code, including the transition to Running. So, gcc now should also complain about the missing definition for Running.
but vs 2003 complains about Running being undefined.
So does VS2008. Frankly, I'm not sure whether GCC is too lazy or VS too eager. But it shouldn't matter, if the whole machine is in one TU, you should be able to fix this by shuffling around includes (unless I'm missing something). HTH, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

So does VS2008. Frankly, I'm not sure whether GCC is too lazy or VS too eager. But it shouldn't matter, if the whole machine is in one TU, you should be able to fix this by shuffling around includes (unless I'm missing something).
Ok. By TU I take that to be one cpp file with its includes. For maintenance reasons it appears the model was broken up into multiple cpp files.
Ok, please disregard my previous post then.
It seems the model was structured under gcc that every inner level is a new header that just includes its parent, but not any children (inners).
Ok, just so that I understand the organization of the GCC source correctly: What does the cpp that contains the call to state_machine<>.initiate() include *directly* and *indirectly*? From your description, it only includes some of the headers defining the states, correct? -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

Hi Andreas, The following is a rough guide to the layout of the code that currently builds under Linux (reactions are not shown). I hope it shows enough details to answer your questions: M.h: struct A1; struct A2; struct A3; struct B0; struct C0; struct M: sc::state_machine< M, A1 > { void start (); ... }; struct A1 : sc::simple_state< A1, M > { A1(); ~A1(); }; A1 : sc::simple_state< A1, M > { A1(); ~A1(); }; struct A2 : sc::simple_state< A2, M > { A2(); ~A2(); }; A2 : sc::simple_state< A2, M > { A2(); ~A2(); }; struct A3 : sc::simple_state< A3, M, mpl::list<B0, C0> > { A3(); ~A3(); }; A3 : sc::simple_state< A3, M, mpl::list<B0, C0> > { A3(); ~A3(); }; B.h: #include "M.h" struct B1; struct B2; struct B3; struct D1; struct B0 : sc::state< B0, A3::orthogonal< 0 >, B1> { B0(my_context ctx); ~B0(); }; B0 : sc::state< B0, A3::orthogonal< 0 >, B1> { B0(my_context ctx); ~B0(); }; struct B1 : sc::state< B1, B0> B1 : sc::state< B1, B0> { B1(my_context ctx); ~B1(); }; struct B2 : sc::state< B2, B0, D1> B2 : sc::state< B2, B0, D1> { B2(my_context ctx); ~B2(); }; struct B3 : sc::state< B3, B0> B3 : sc::state< B3, B0> { B3(my_context ctx); ~B3(); }; C.h: #include "M.h" struct C1; struct C2; struct C0 : sc::state< C0, A3::orthogonal< 1 >, C1> { C0(my_context ctx); ~C0(); }; C0 : sc::state< C0, A3::orthogonal< 1 >, C1> { C0(my_context ctx); ~C0(); }; struct C1 : sc::state< C1, C0> C1 : sc::state< C1, C0> { C1(my_context ctx); ~C1(); }; struct C2 : sc::state< C2, C0> C2 : sc::state< C2, C0> { C2(my_context ctx); ~C2(); }; D.h: #include "B.h" struct D2; struct D1 : sc::state< D1, B2> D1 : sc::state< D1, B2> { D1(my_context ctx); ~D1(); }; struct D2 : sc::state< D2, B2> D2 : sc::state< D2, B2> { D2(my_context ctx); ~D2(); }; M.cpp: #include "M.h" #include "B.h" #include "C.h" void M::start () { initiate (); } <any other M class related stuff> A.cpp #include "M.h" #include "B.h" #include "C.h" <all A class related stuff> B.cpp #include "B.h" #include "D.h" <all B class related stuff> C.cpp #include "C.h" <all C class related stuff> D.cpp #include "D.h" <all D class related stuff> main.cpp: #include "M.h" int main () { M m; m.start (); return 0; } thirdparty.cpp: #include "M.h" M *m = 0; Under Windows the following errors are produced: thirdparty.cpp, main.cpp, C.cpp: c:\PXI Code Base\CommonPlatform\include\boost\statechart\simple_state.hpp(893) : error C2027: use of undefined type 'B0' A.cpp, M.cpp: c:\PXI Code Base\CommonPlatform\include\boost\statechart\simple_state.hpp(893) : error C2027: use of undefined type 'D1' B.cpp: c:\PXI Code Base\CommonPlatform\include\boost\statechart\simple_state.hpp(893) : error C2027: use of undefined type 'C0' Simon

Hi Simon [snip example code] Thanks, I'll provide you with the minimal set of modifications that are needed to make this compile on VS2008 (I no longer own any of the older versions), while keeping the modularization intact. I don't have enough time right now but I should get to it tomorrow, so you should have a workable solution before March 15th, midnight UTC. If you can't wait until then, the basic principle is outlined here: <http://www.boost.org/doc/libs/1_42_0/libs/statechart/doc/tutorial.html#SpreadingAStateMachineOverMultipleTranslationUnits> Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

Hi Simon Unfortunately, I cannot reproduce your errors with Visual Studio 2008. See attached zip for the exact code I tested. The code is pretty much equivalent to yours, the only deviation is that in my project did not add A.cpp (because it contains the same code as M.cpp). Could you please test the attached code with your version of Visual Studio and see whether you still get those errors? Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

Hi Andreas, Thankyou for your help. The code example previously sent was providing an overview of the code layout (transitions removed). Adding transitions shows the problem under vc2003 e.g: #ifndef M_HPP_INCLUDED M_HPP_INCLUDED #define M_HPP_INCLUDED M_HPP_INCLUDED #include <boost/statechart/state_machine.hpp> <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> <boost/statechart/simple_state.hpp> #include <boost/statechart/custom_reaction.hpp> <boost/statechart/custom_reaction.hpp> #include <boost/statechart/event.hpp> <boost/statechart/event.hpp> #include <boost/statechart/transition.hpp> <boost/statechart/transition.hpp> namespace sc = boost::statechart; sc = boost::statechart; namespace mpl = boost::mpl; mpl = boost::mpl; struct A1; A1; struct A2; A2; struct A3; A3; struct B0; B0; struct C0; C0; struct EvA1ToA2 : sc::event< EvA1ToA2 > {}; EvA1ToA2 : sc::event< EvA1ToA2 > {}; struct EvA2ToA3 : sc::event< EvA2ToA3 > {}; EvA2ToA3 : sc::event< EvA2ToA3 > {}; struct EvA3ToA1 : sc::event< EvA3ToA1 > {}; EvA3ToA1 : sc::event< EvA3ToA1 > {}; struct M: sc::state_machine< M, A1 > { M () {} ~M () {} void start (); }; M: sc::state_machine< M, A1 > { M () {} ~M () {} void start (); }; void start (); }; struct A1 : sc::simple_state< A1, M > { typedef sc::transition< EvA1ToA2, A2 > reactions; A1() {} ~A1() {} }; A1 : sc::simple_state< A1, M > { typedef sc::transition< EvA1ToA2, A2 > reactions; A1() {} ~A1() {} }; typedef sc::transition< EvA1ToA2, A2 > reactions; A1() {} ~A1() {} }; struct A2 : sc::simple_state< A2, M > { typedef sc::transition< EvA2ToA3, A3 > reactions; A2() {} ~A2() {} }; A2 : sc::simple_state< A2, M > { typedef sc::transition< EvA2ToA3, A3 > reactions; A2() {} ~A2() {} }; typedef sc::transition< EvA2ToA3, A3 > reactions; A2() {} ~A2() {} }; struct A3 : sc::simple_state< A3, M, mpl::list<B0, C0> > { typedef sc::transition< EvA3ToA1, A1 > reactions; A3() {} ~A3() {} }; A3 : sc::simple_state< A3, M, mpl::list<B0, C0> > { typedef sc::transition< EvA3ToA1, A1 > reactions; A3() {} ~A3() {} }; typedef sc::transition< EvA3ToA1, A1 > reactions; A3() {} ~A3() {} }; #endif Regards, Simon -----Original Message----- From: Andreas Huber <ahd6974-spamboostorgtrap@yahoo.com> To: boost@lists.boost.org Sent: Mon, Mar 15, 2010 8:43 pm Subject: Re: [boost] [statechart] Undefined type Hi Simon Unfortunately, I cannot reproduce your errors with Visual Studio 2008. See attached zip for the exact code I tested. The code is pretty much equivalent to yours, the only deviation is that in my project did not add A.cpp (because it contains the same code as M.cpp). Could you please test the attached code with your version of Visual Studio and see whether you still get those errors? Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header. _______________________________________________ nsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Thankyou for your help. The code example previously sent was providing an overview of the code layout (transitions removed). Adding transitions shows the problem under vc2003 e.g:
Please see the attached code, tested with VS2008. I introduced a level of indirection with the B0Dummy & C0Dummy states, declared in the M.hpp header. The trick is to have these states post an event in their entry action and then use a custom_reaction to immediately transition to B0 & C0. This works because now the transition target only needs to be mentioned in the cpp. Yes, the definition of two additional states & 2 events is a bit cumbersome, but this is sort of a worst case. E.g. it would have been much easier to implement A2 & A3 in their own CPPs, because there you'd only have to replace a transition with a custom_reaction. HTH, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.
participants (2)
-
Andreas Huber
-
s_a_white@email.com