Separating User Code from Generated Code into Headers and Source Files

Hi

Just wanted to get opinions from C++ experts about the following:

I am building a simple code generator akin to the orocreate-pkg. The
code generator can be initialized with a file defining an arbitrary
number of ports. The list of ports is mutable and thus the ports
generated as C++ code are mutable too. The end product of code
generation is a TaskContext. The code generation is only allowed to
modifiy the header file for the TaskContext. A user is not expected to
edit the header file. All user code is added by the using in the
source file.

This is the initial header/source combination that compiles. Please
check it over and comment.

===HEADER===

/*
* Task_R_RT.hpp
*
* Created on: Jul 17, 2011
* Author: hugo
*/

#ifndef TASK_R_RT_HPP_
#define TASK_R_RT_HPP_

#include <rtt/RTT.hpp>
#include <rtt/Component.hpp>

using namespace RTT;

namespace KUL
{
class Task_R_RT: public RTT::TaskContext
{
InputPort<char> InPortB;
InputPort<char> InPortC;
OutputPort<char> OutPortA;

public:
Task_R_RT(const string& name);
};

Task_R_RT::Task_R_RT(string const& name = "Task_B") :
TaskContext(name)
{
this->ports()->addPort("InPortB", InPortB).doc(
"Input Port that does *not* raise an event.");
this->ports()->addPort("InPortC", InPortC).doc(
"Input Port that does *not* raise an event.");
this->ports()->addPort("OutPortA", OutPortA).doc(
"Output Port, here write our data to.");

}
}

ORO_CREATE_COMPONENT(KUL::Task_R_RT)

#endif /* TASK_R_RT_HPP_ */

====SOURCE====

/*
* Task_R_RT.cpp
*
* Created on: Jul 17, 2011
* Author: hugo
*/

#include <iostream>
#include "Task_R_RT.hpp"

bool configureHook()
{
std::cout << "Task_A configured !" << std::endl;
return true;
}

bool startHook()
{
std::cout << "Task_A started !" << std::endl;
return true;
}

void updateHook()
{
std::cout << "Task_A executes updateHook !" << std::endl;
}

void stopHook()
{
std::cout << "Task_A executes stopping !" << std::endl;
}

void cleanupHook()
{
std::cout << "Task_A cleaning up !" << std::endl;
}

-------

Some observations and question:

* KUL here would represent the namespace for an Orocos package. Thus
every Orocos package would have its own specific namespace.

* Here we are only create one component in a library yet a package can
have multiple components. It is my understanding there is a separate
macro for combining multiple component into one package. Where would
that macro be written in the header file(s) or would it be written
somewhere else?

* Do the methods in Task_R_RT.cpp [starHook(), updateHook()] actually
override the protected methods of the same names in
rtt/base/TaskCore.hpp?

-H

Separating User Code from Generated Code into Headers and Source

On 07/19/2011 10:12 PM, Hugo Garcia wrote:
> Hi
>
> Just wanted to get opinions from C++ experts about the following:
>
> I am building a simple code generator akin to the orocreate-pkg. The
> code generator can be initialized with a file defining an arbitrary
> number of ports. The list of ports is mutable and thus the ports
> generated as C++ code are mutable too. The end product of code
> generation is a TaskContext. The code generation is only allowed to
> modifiy the header file for the TaskContext. A user is not expected to
> edit the header file. All user code is added by the using in the
> source file.
Can I respectfully suggest that you have a look at orogen, which already
does more or less exactly that ?

Sylvain

Separating User Code from Generated Code into Headers and Source

On Thu, Jul 28, 2011 at 11:31, Sylvain Joyeux <sylvain [dot] joyeux [..] ...> wrote:
> On 07/19/2011 10:12 PM, Hugo Garcia wrote:
>>
>> Hi
>>
>> Just wanted to get opinions from C++ experts about the following:
>>
>> I am building a simple code generator akin to the orocreate-pkg. The
>> code generator can be initialized with a file defining an arbitrary
>> number of ports. The list of ports is mutable and thus the ports
>> generated as C++ code are mutable too. The end product of code
>> generation is a TaskContext. The code generation is only allowed to
>> modifiy the header file for the TaskContext. A user is not expected to
>> edit the header file. All user code is added by the using in the
>> source file.
>
> Can I respectfully suggest that you have a look at orogen, which already
> does more or less exactly that ?
>
> Sylvain
>

I did but the way the file for generating the code is created in a
different manner than your approach. The end result is still the same.

-H

Separating User Code from Generated Code into Headers and Source

On 07/28/2011 08:11 PM, Hugo Garcia wrote:
> On Thu, Jul 28, 2011 at 11:31, Sylvain Joyeux<sylvain [dot] joyeux [..] ...> wrote:
>> On 07/19/2011 10:12 PM, Hugo Garcia wrote:
>>> Hi
>>>
>>> Just wanted to get opinions from C++ experts about the following:
>>>
>>> I am building a simple code generator akin to the orocreate-pkg. The
>>> code generator can be initialized with a file defining an arbitrary
>>> number of ports. The list of ports is mutable and thus the ports
>>> generated as C++ code are mutable too. The end product of code
>>> generation is a TaskContext. The code generation is only allowed to
>>> modifiy the header file for the TaskContext. A user is not expected to
>>> edit the header file. All user code is added by the using in the
>>> source file.
>> Can I respectfully suggest that you have a look at orogen, which already
>> does more or less exactly that ?
>>
>> Sylvain
>>
> I did but the way the file for generating the code is created in a
> different manner than your approach. The end result is still the same.
I don't understand that statement.

orogen is mostly an API. You can parse any file description, create
(programatically) an orogen spec and generate the corresponding code.

Creating a parallel code generator is just fragmenting the "model-based"
tooling in the orocos ecosystem, which sucks big time.

Sylvain

Separating User Code from Generated Code into Headers and Source

On Fri, 29 Jul 2011, Sylvain Joyeux wrote:

> On 07/28/2011 08:11 PM, Hugo Garcia wrote:
>> On Thu, Jul 28, 2011 at 11:31, Sylvain Joyeux<sylvain [dot] joyeux [..] ...> wrote:
>>> On 07/19/2011 10:12 PM, Hugo Garcia wrote:
>>>> Hi
>>>>
>>>> Just wanted to get opinions from C++ experts about the following:
>>>>
>>>> I am building a simple code generator akin to the orocreate-pkg. The
>>>> code generator can be initialized with a file defining an arbitrary
>>>> number of ports. The list of ports is mutable and thus the ports
>>>> generated as C++ code are mutable too. The end product of code
>>>> generation is a TaskContext. The code generation is only allowed to
>>>> modifiy the header file for the TaskContext. A user is not expected to
>>>> edit the header file. All user code is added by the using in the
>>>> source file.
>>> Can I respectfully suggest that you have a look at orogen, which already
>>> does more or less exactly that ?
>>>
>>> Sylvain
>>>
>> I did but the way the file for generating the code is created in a
>> different manner than your approach. The end result is still the same.
> I don't understand that statement.
>
> orogen is mostly an API. You can parse any file description, create
> (programatically) an orogen spec and generate the corresponding code.
>
> Creating a parallel code generator is just fragmenting the "model-based"
> tooling in the orocos ecosystem, which sucks big time.

This is a dangerous statement :-) You have basically done the same thing:
there are tons of code generators "out there", in large-scale ecosystems
like Eclipse, for example, that you could have used. And since Hugo's job
is to integrate Orocos into the Eclipse ecosystem, it makes sense to use
the Model-to-Model and Model-to-Text tools that are supported there. The
issues to be still researched are: (i) is there a real difference in the
quality and sustainability of different model transformation tools, and
(ii) can we come up with a code generation workflow that is independent of
the transformation tool that is being used.

Note that I am just observing, not judging. :-)

> Sylvain

Herman

Separating User Code from Generated Code into Headers and Source

On Tue, Jul 19, 2011 at 10:12 PM, Hugo Garcia <hugo [dot] a [dot] garcia [..] ...> wrote:
> Hi
>
> Just wanted to get opinions from C++ experts about the following:
>
> I am building a simple code generator akin to the orocreate-pkg. The
> code generator can be initialized with a file defining an arbitrary
> number of ports. The list of ports is mutable and thus the ports
> generated as C++ code are mutable too. The end product of code
> generation is a TaskContext. The code generation is only allowed to
> modifiy the header file for the TaskContext. A user is not expected to
> edit the header file. All user code is added by the using in the
> source file.
>
> This is the initial header/source combination that compiles. Please
> check it over and comment.

It compiles but it's completely crap. This looks like an orocos-users
question btw.

>
> ===HEADER===
>
> /*
>  * Task_R_RT.hpp
>  *
>  *  Created on: Jul 17, 2011
>  *      Author: hugo
>  */
>
> #ifndef TASK_R_RT_HPP_
> #define TASK_R_RT_HPP_
>
> #include <rtt/RTT.hpp>
> #include <rtt/Component.hpp>

This include belongs in the .cpp file

>
> using namespace RTT;
>
> namespace KUL
> {
>    class Task_R_RT: public RTT::TaskContext
>    {
>        InputPort<char> InPortB;
>        InputPort<char> InPortC;
>        OutputPort<char> OutPortA;
>
>    public:
>        Task_R_RT(const string& name);
>    };
>
>    Task_R_RT::Task_R_RT(string const& name = "Task_B") :
>            TaskContext(name)
>    {
>        this->ports()->addPort("InPortB", InPortB).doc(
>                "Input Port that does *not* raise an event.");
>        this->ports()->addPort("InPortC", InPortC).doc(
>                "Input Port that does *not* raise an event.");
>        this->ports()->addPort("OutPortA", OutPortA).doc(
>                "Output Port, here write our data to.");
>
>    }

This function would end up in every compilation unit. It belongs in
the .cpp file too.

> }
>
> ORO_CREATE_COMPONENT(KUL::Task_R_RT)

This macro belongs in the .cpp file.

>
> #endif /* TASK_R_RT_HPP_ */
>
>
> ====SOURCE====
>
> /*
>  * Task_R_RT.cpp
>  *
>  *  Created on: Jul 17, 2011
>  *      Author: hugo
>  */
>
> #include <iostream>
> #include "Task_R_RT.hpp"
>
> bool configureHook()
> {
>    std::cout << "Task_A configured !" << std::endl;
>    return true;
> }

This doesn't do what you intend. You need to declare the
configureHook() function in your class and then implement it with:

bool Task_R_RT::configureHook() { ... }

>
> bool startHook()
> {
>    std::cout << "Task_A started !" << std::endl;
>    return true;
> }
>
> void updateHook()
> {
>    std::cout << "Task_A executes updateHook !" << std::endl;
> }
>
> void stopHook()
> {
>    std::cout << "Task_A executes stopping !" << std::endl;
> }
>
> void cleanupHook()
> {
>    std::cout << "Task_A cleaning up !" << std::endl;
> }
>
> -------
>
> Some observations and question:
>
> * KUL here would represent the namespace for an Orocos package. Thus
> every Orocos package would have its own specific namespace.

That's wise.

>
> * Here we are only create one component in a library yet a package can
> have multiple components. It is my understanding there is a separate
> macro for combining multiple component into one package. Where would
> that macro be written in the header file(s) or would it be written
> somewhere else?

See http://www.orocos.org/stable/documentation/rtt/v2.x/api/html/Component_8...
and especially
http://www.orocos.org/stable/documentation/rtt/v2.x/api/html/Component_8...

>
> * Do the methods in Task_R_RT.cpp [starHook(), updateHook()] actually
> override the protected methods of the same names in
> rtt/base/TaskCore.hpp?

No. They are free functions, they don't belong to any class.

Peter
--
Orocos-Dev mailing list
Orocos-Dev [..] ...
http://lists.mech.kuleuven.be/mailman/listinfo/orocos-dev

Separating User Code from Generated Code into Headers and Source

Iteration #2

===Header===

/*
* Controller_RT.hpp
*
*/

#ifndef CONTROLLER_RT_HPP_
#define CONTROLLER_RT_HPP_

using namespace RTT;

namespace YouBotMotion
{
class Controller_RT: public RTT::TaskContext
{
InputPort<float> Position;
OutputPort<float> Velocity;

public:
Controller_RT(const string& name);

bool configureHook();
bool startHook();
void updateHook();
void stopHook();
void cleanupHook();
};
}

#endif /* CONTROLLER_RT_HPP_ */

===SOURCE===

#include <rtt/RTT.hpp>
#include <rtt/Component.hpp>
#include <iostream>
#include "Controller_RT.hpp"

using namespace RTT;
using namespace YouBotMotion;

Controller_RT::Controller_RT(string const& name = "Controller") :
TaskContext(name)
{
this->ports()->addPort( "Position", Position ).doc( "Input Port that
does *not* raise an event." );
this->ports()->addPort( "Velocity", Velocity ).doc( "Output Port,
here write our data to." );
std::cout << "Controller constructed !" <<std::endl;
}

bool Controller_RT::configureHook()
{
std::cout << "Controller configured !" <<std::endl;
return true;
}

bool Controller_RT::startHook()
{
std::cout << "Controller started !" <<std::endl;
return true;
}

void Controller_RT::updateHook()
{
std::cout << "Controller executes updateHook !" <<std::endl;
}

void Controller_RT::stopHook()
{
std::cout << "Controller executes stopping !" <<std::endl;
}

void Controller_RT::cleanupHook()
{
std::cout << "Controller cleaning up !" <<std::endl;
}

ORO_CREATE_COMPONENT(YouBotMotion::Controller_RT)

=======