Your question sounds more like a C question than a Perl question.

Yes, that's why I marked my posting as off-topic.

One idea is to have a single config file in some easy to understand format and have Perl write the .c and .h code for this initialization and loop run code from that.

Yes, that would be possible.

I've considered generating the entire main.c from the module sources using a perl script. But we usually put some application-specific code into main that does not fit elsewhere, so a generated main.c is not acceptable, and so I gave up that idea.

But you are right, I could get away by simply reading all module file names from the AS project file, extracting XXX_Init() functions from the modules, and generate an auxillary file that basically just contains an array of pointers to init functions. That would work without messing with the linker, and I wouldn't even need a config file. We already do something similar to assemble a version number.

I could even go one step back and assemble two arrays, one for init functions, one for run functions. That way, our software would still have two distinct global phases, one init, one run, and except for making all init and run functions return void and taking no arguments, no changes to existing modules would be needed.

But one of the reasons to get rid of the two distinct global phases is that some critical modules need the services of other modules while initializing, and those services are available only in the run phase. So we work around by moving part of the initialization to the run function of those modules, and prevent calling most run functions until those critical modules are ready. Manually, of course. -- Boy, that's hard to express in english. In code, it looks about like this:

int main(void) { SystemInit(); Foo_Init(); Bar_Init(); Baz_Init(); // and so on for(;;) { Foo_Run(); //< module that "Bar" depends on Bar_Run(); //< critical module if (Bar_IsReady()) { Baz_Run(); //< "normal" module // and all other "normal" modules } } }

Other modules originally had a long-running init function, but no run function. Again, we hacked around by moving parts of the init function to a new run function that will be called only until the long-running init is done:

int main(void) { SystemInit(); Foo_Init(); Bar_Init(); Baz_Init(); Abc_Init(); // and so on for(;;) { Foo_Run(); //< module that "Bar" depends on Bar_Run(); //< critical module if (!Abc_IsDone()) { Abc_Run(); } if (Bar_IsReady()) { Baz_Run(); //< "normal" module // and all other "normal" modules } } }

I'm not willing to go back to that situation. The trick of replacing init functions with run functions in the function pointer array automatically resolves that problems. Any module can use any run-time services of any other module it depends on from its init function, and each init function can run as long as required.

But I will definitly discuss that idea of a perl script instead of the linker for generating the function pointer array at work. Both ways need to touch modules that expect arguments for XXX_Init() and/or XXX_Run(). Both ways need to touch modules that depend on other modules to add the dependency statements. And there is also a minor issue with the code that generates the version number, so we will probably have to scan each module during build anyway. Both could be merged into a single perl script.

Linker scripts are part of each project, they are in a repository like all other source files, so modifying them is no big deal, and we already modify the linker scripts for other reasons. We also use perl as part of the build process, with all scripts in the repository. Both ways are possible, but both look like voodoo to interns and freshly hired developers that know C only as a subset of desktop C++, and to the old developers whose main experience is with DOS/Win-16 and 8-bit microcontrollers with horrible toolchains. 32-bit ARM and GCC are significantly different, and require a different way of doing things. So maintainability will be part of the discussion.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

In reply to Re^2: [OT] Abusing GNU compiler and linker: Make the linker generate an array of function pointers by afoken
in thread [OT] Abusing GNU compiler and linker: Make the linker generate an array of function pointers by afoken

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.