Unix Programming - Not a flame war, but perl vs m4

This is Interesting: Free IT Magazines  
Home > Archive > Unix Programming > March 2006 > Not a flame war, but perl vs m4





You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

Author Not a flame war, but perl vs m4
billy

2006-02-28, 7:51 am

I have a project that requires me to write a makefile that will include
some 280 other makefiles. This is used to allow for maximum
utilization or multi tasking (-j --max-load)
What I am doing is to convert a system that was created @ 1980. It
doesn''t work so well now. It uses over 450 independent makefiles with
interdependencies that were not captured. That's why the single
makefiel that iincludes 280 other make.include files. I've been
writing in PERL for over 15 years, but I see a lot of traffic about m4.

To create the makefiles, which would be better, PERL or m4?

perl advantages. I know it very well.
m4 disadvantages. I can hardly spell m4. never even done "hello world"

The current build system has over 300 setup files that explain how to
make modifications to the skeleton, 50, makefiles. I would like to use
these skeleton and setup files to generate a complete set of makefiles
that will be static. But I need to regenerate them when I find that
some tweeking is necessary for a particular rule/dependency.
if-then-elsif-elsif-...else LARGE

BTW this build has over 40,000 static files and 10,000 auto generated
from an Oracle database. Current build time is 12 hours with no
parallazation.

So back to my original question
Which would serve me better? m4 or perl.

What brought m4 to my thoughts was a tool MakeXS that is supposed to be
helpful in generating makefiles. But it uses recursion. We have
deemed that recursive makefiles is not a good thing for
interdependencies between 100+ subdirectories.

Michael Zawrotny

2006-03-03, 6:42 pm

On 28 Feb 2006 04:23:03 -0800, billy <bp1497@att.com> wrote:

[ snip description of large build system ]

> To create the makefiles, which would be better, PERL or m4?
>
> PERL advantages. I know it very well.
> m4 disadvantages. I can hardly spell m4. never even done "hello world"


I would recommend PERL with Template Toolkit. That will allow you to
abstract out any common features of the makefiles and TT also has a
program (ttree) that will run through a directory and only re-generate
the files that are out of date relative to their template, similar to
what make does with source and object files. O'Reilly has a book on
TT; the sample chapter and many of the examples have to do with web
development, but don't let that turn you off. It can do a lot more
than generate html.

Several years ago I set up a system to generate firewall rules from a
couple of files that would get processed by m4. I don't think that I
would ever do it that way again. It's personal opinion, but for me
the quoting and substitution was an enormous pain.


Mike


--
Michael Zawrotny
Institute of Molecular Biophysics
Florida State university | email: zawrotny@sb.fsu.edu
Tallahassee, FL 32306-4380 | phone: (850) 644-0069
phil-news-nospam@ipal.net

2006-03-03, 6:42 pm

On 28 Feb 2006 04:23:03 -0800 billy <bp1497@att.com> wrote:

| I have a project that requires me to write a makefile that will include
| some 280 other makefiles. This is used to allow for maximum
| utilization or multi tasking (-j --max-load)
| What I am doing is to convert a system that was created @ 1980. It
| doesn''t work so well now. It uses over 450 independent makefiles with
| interdependencies that were not captured. That's why the single
| makefiel that iincludes 280 other make.include files. I've been
| writing in PERL for over 15 years, but I see a lot of traffic about m4.
|
| To create the makefiles, which would be better, PERL or m4?
|
| PERL advantages. I know it very well.
| m4 disadvantages. I can hardly spell m4. never even done "hello world"

Perl because you know it better. 15 years sounds like you know it quite
well. If you know what to do to make it work in Perl, by all means go
with it.

I don't know PERL (nor do I want to), so for me it would be something
else. I typically generate stuff like Makefile and headers in bash,
pike, or good ole C. And that's because I know them well and I can
make them do what I need easily. For things that need to run on other
people's computers, I generally have to bypass pike since it is still
not universally available. But a subset of bash (eg. just sh) usually
is, and bash itself usually is on Linux, so I end up using that or C.


| What brought m4 to my thoughts was a tool MakeXS that is supposed to be
| helpful in generating makefiles. But it uses recursion. We have
| deemed that recursive makefiles is not a good thing for
| interdependencies between 100+ subdirectories.

I suspect recursive makefiles could be a problem, but I never did any
analysis of that. I pretty much have moved to making a single flat
Makefile for my projects (but the biggest of them is currently at 1866
files). One big flat Makefile for it does tend to look ugly.

--
-----------------------------------------------------------------------------
| Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
Roger Leigh

2006-03-03, 6:42 pm

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

"billy" <bp1497@att.com> writes:

> To create the makefiles, which would be better, PERL or m4?
>
> PERL advantages. I know it very well.


As others have said, this is a very good reason for going with Perl.

> m4 disadvantages. I can hardly spell m4. never even done "hello world"


I really like m4, but it is difficult to debug, and quoting is quite
hard. It's also not a real programming language; it's a fast macro
processor to expand macros, which you can define externally or inline
in the code being processed. That said, it does support conditionals
I've used it in the pass to preprocess C++ source, where a few simple
macros in a class definition or code could expand into a whole set of
complex methods.

For what it does, m4 is likely to be faster than Perl, but if you
weigh that against the ease of maintenance (wow, I never thought I'd
say that about Perl!), and your familiarity with Perl, PERL is the
logical choice.


Just as an example, here's a code generator. Notice how the C++ code
is mixed with the m4; you would scatter those macros throughout the
source file. These expand into a whole set of class definitions and
methods inline in the C++ source. And yes, it is truly disgusting!

However, if you find that a lot of your files contain what is
basically very customised and repetitive boilerplate, a set of m4
macros can be a very handy feature.


- --------
m4_divert(-1)m4_dnl


m4_dnl Set quoting characters.
m4_changequote([, ])m4_dnl


m4_dnl Output streams
m4_define([CG_DIVERT_GET], [1])m4_dnl
m4_define([CG_DIVERT_SET], [2])m4_dnl
m4_define([CG_DIVERT_SIGNAL], [3])m4_dnl
m4_define([CG_DIVERT_HANDLER], [4])m4_dnl
m4_define([CG_DIVERT_PROPERTY], [5])m4_dnl
m4_define([CG_DIVERT_PROPERTYDEF], [6])m4_dnl
m4_define([CG_DIVERT_TIE], [7])m4_dnl


m4_dnl Set up variable macros
m4_define([CG_SETUP], [m4_dnl
m4_pushdef([CG_TYPE], [$1])m4_dnl
m4_pushdef([CG_PROPERTY], [m4_patsubst([pqxxobject::ptr_field<$1>], [>>], [> >])])m4_dnl
m4_pushdef([CG_NAME], [$2])m4_dnl
m4_ifelse([$3], [], [m4_pushdef([CG_METHODS], [[get], [set], [signal], [handler], [property], [property_def], [tie_changed], [tie_handler]])],m4_dnl
[m4_pushdef([CG_METHODS], [$3])])m4_dnl
m4_ifelse([ref], [$4], [m4_pushdef([CG_ARGDEF], [CG_TYPE& ])m4_dnl
m4_pushdef([CG_CONSTARGDEF], [const CG_ARGDEF])],m4_dnl
[constref], [$4], [m4_pushdef([CG_ARGDEF], [const CG_TYPE& ])m4_dnl
m4_pushdef([CG_CONSTARGDEF], [CG_ARGDEF])],m4_dnl
[ptr], [$4], [m4_pushdef([CG_ARGDEF], [CG_TYPE *])m4_dnl
m4_pushdef([CG_CONSTARGDEF], [const CG_ARGDEF])],m4_dnl
[constptr], [$4], [m4_pushdef([CG_ARGDEF], [const CG_TYPE *])m4_dnl
m4_pushdef([CG_CONSTARGDEF], [CG_ARGDEF])],m4_dnl
m4_dnl Fallback to value
[m4_pushdef([CG_ARGDEF], [CG_TYPE ])m4_dnl
m4_pushdef([CG_CONSTARGDEF], [CG_ARGDEF])])m4_dnl
m4_ifelse([$5], [], [m4_pushdef([CG_DESCRIPTION], [$5])], m4_pushdef([CG_DESCRIPTION], []))m4_dnl
])m4_dnl


m4_define([CG_CLEANUP], [m4_dnl
m4_popdef([CG_DESCRIPTION])m4_dnl
m4_popdef([CG_CONSTARGDEF])m4_dnl
m4_popdef([CG_ARGDEF])m4_dnl
m4_popdef([CG_METHODS])m4_dnl
m4_popdef([CG_NAME])m4_dnl
m4_popdef([CG_TYPE])m4_dnl
])m4_dnl


m4_define([CG_OUTPUT_DECLARATIONS], [m4_dnl
m4_ifelse([$1], , , [m4_dnl
m4_ifelse([$1], [get], [m4_divert(CG_DIVERT_GET)m4_dnl
/**
* Get the value of CG_NAME[].
m4_ifelse([]CG_DESCRIPTION[], [],m4_dnl
[], [ * ]CG_DESCRIPTION[
])m4_dnl
* @returns the value of CG_NAME[].
*/
CG_CONSTARGDEF[]get_[]CG_NAME[]() const;

], [$1], [get_mod], [m4_divert(CG_DIVERT_GET)m4_dnl
/**
* Get the value of CG_NAME[].
m4_ifelse([]CG_DESCRIPTION[], [],m4_dnl
[], [ * ]CG_DESCRIPTION[
])m4_dnl
* @returns the value of CG_NAME[].
*/
CG_ARGDEF[]get_[]CG_NAME[]();

], [$1], [set], [m4_divert(CG_DIVERT_SET)m4_dnl
/**
* Set the value of CG_NAME[].
m4_ifelse([]CG_DESCRIPTION[], [],m4_dnl
[], [ * ]CG_DESCRIPTION[
])m4_dnl
* @param CG_NAME[] the value to set.
*/
void set_[]CG_NAME[](CG_CONSTARGDEF[]CG_NAME);

], [$1], [signal], [m4_divert(CG_DIVERT_SIGNAL)m4_dnl
/**
* The "changed" signal of CG_NAME[].
m4_ifelse([]CG_DESCRIPTION[], [],m4_dnl
[], [ * ]CG_DESCRIPTION[
])m4_dnl
* @returns the "changed" signal of CG_NAME[].
*/
SigC::Signal0<void>& signal_[]CG_NAME[]_changed();

], [$1], [handler], [m4_divert(CG_DIVERT_HANDLER)m4_dnl
/**
* Virtual method called when the "changed" signal of CG_NAME is emitted.
* This method may be overridden in derived classes.
m4_ifelse([]CG_DESCRIPTION[], [],m4_dnl
[], [ * ]CG_DESCRIPTION[
])m4_dnl
*/
virtual void on_[]CG_NAME[]_changed();

], [$1], [property], [m4_divert(CG_DIVERT_PROPERTY)m4_dnl
/**
* Get the property (field) containing CG_NAME[].
m4_ifelse([]CG_DESCRIPTION[], [],m4_dnl
[], [ * ]CG_DESCRIPTION[
])m4_dnl
* @returns the property containing CG_NAME[].
*/
CG_PROPERTY& property_[]CG_NAME[]();

], [$1], [property_def], & #91;m4_divert(CG_DIVERT_PROPERTYDEF)m4_d
nl
// Connect to "changed" signal for CG_NAME[].
CG_PROPERTY m_[]CG_NAME;

])m4_dnl
m4_divert(0)m4_dnl
CG_OUTPUT_DECLARATIONS(m4_shift($@))])m4
_dnl
])m4_dnl


m4_dnl
m4_dnl $1=type
m4_dnl $2=name
m4_dnl $3=methods: one or more of: get|get_mod|set|signal|handler|property|
property_def
m4_dnl $4=argtype: value|ref|constref|ptr|constptr
m4_define([CG_DECLARE], [m4_dnl
CG_SETUP($@)m4_dnl
CG_OUTPUT_DECLARATIONS(CG_METHODS)m4_dnl

CG_CLEANUP])m4_dnl



m4_define([CG_OUTPUT_DEFINITIONS], [m4_dnl
m4_ifelse([$1], , , [m4_dnl
m4_ifelse([$1], [get], [m4_divert(CG_DIVERT_GET)m4_dnl
CG_CONSTARGDEF[]CG_CLASSNAME::get_[]CG_NAME[]() const
{
return m_[]CG_NAME;
}

], [$1], [get_mod], [m4_divert(CG_DIVERT_GET)m4_dnl
CG_ARGDEF[]CG_CLASSNAME::get_[]CG_NAME[]()
{
return m_[]CG_NAME[].get_value();
}

], [$1], [set], [m4_divert(CG_DIVERT_SET)m4_dnl
void CG_CLASSNAME::set_[]CG_NAME[](CG_CONSTARGDEF[]CG_NAME)
{
m_[]CG_NAME = CG_NAME;
}

], [$1], [signal], [m4_divert(CG_DIVERT_SIGNAL)m4_dnl
SigC::Signal0<void>& CG_CLASSNAME::signal_[]CG_NAME[]_changed()
{
return m_[]CG_NAME.signal_changed();
}

], [$1], [handler], [m4_divert(CG_DIVERT_HANDLER)m4_dnl
void CG_CLASSNAME::on_[]CG_NAME[]_changed()
{
}

], [$1], [property], [m4_divert(CG_DIVERT_PROPERTY)m4_dnl
CG_PROPERTY& CG_CLASSNAME::property_[]CG_NAME[]()
{
return m_[]CG_NAME;
}

], [$1], [tie_changed], [m4_divert(CG_DIVERT_TIE)m4_dnl
m_[]CG_NAME[].signal_changed().connect
( SigC::slot(*this, &pqxxobject::row_base::raise_changed) );

], [$1], [tie_handler], [m4_divert(CG_DIVERT_TIE)m4_dnl
m_[]CG_NAME[].signal_changed().connect
( SigC::slot(*this, &[]CG_CLASSNAME[]::on_[]CG_NAME[]_changed) );

])m4_dnl
m4_divert(0)m4_dnl
CG_OUTPUT_DEFINITIONS(m4_shift($@))])m4_
dnl
])m4_dnl


m4_define([CG_OUTPUT_INLINES], [m4_dnl
m4_ifelse([$1], , , [m4_dnl
m4_ifelse([$1], [get], [m4_divert(CG_DIVERT_GET)m4_dnl
CG_CONSTARGDEF[]get_[]CG_NAME[]() const
{
return m_[]CG_NAME;
}

], [$1], [get_mod], [m4_divert(CG_DIVERT_GET)m4_dnl
CG_ARGDEF[]get_[]CG_NAME[]()
{
return m_[]CG_NAME[].get_value();
}

], [$1], [set], [m4_divert(CG_DIVERT_SET)m4_dnl
void set_[]CG_NAME[](CG_CONSTARGDEF[]CG_NAME)
{
m_[]CG_NAME = CG_NAME;
}

], [$1], [signal], [m4_divert(CG_DIVERT_SIGNAL)m4_dnl
SigC::Signal0<void>& signal_[]CG_NAME[]_changed()
{
return m_[]CG_NAME.signal_changed();
}

], [$1], [handler], [m4_divert(CG_DIVERT_HANDLER)m4_dnl
void on_[]CG_NAME[]_changed()
{
}

], [$1], [property], [m4_divert(CG_DIVERT_PROPERTY)m4_dnl
CG_PROPERTY& property_[]CG_NAME[]()
{
return m_[]CG_NAME;
}

], [$1], [property_def], & #91;m4_divert(CG_DIVERT_PROPERTYDEF)m4_d
nl
CG_PROPERTY m_[]CG_NAME;

], [$1], [tie_changed], [m4_divert(CG_DIVERT_TIE)m4_dnl
m_[]CG_NAME[].signal_changed().connect
( SigC::slot(*this, &pqxxobject::row_base::raise_changed) );

], [$1], [tie_handler], [m4_divert(CG_DIVERT_TIE)m4_dnl
m_[]CG_NAME[].signal_changed().connect
( SigC::slot(*this, &[]CG_CLASSNAME[]::on_[]CG_NAME[]_changed) );

])m4_dnl
m4_divert(0)m4_dnl
CG_OUTPUT_INLINES(m4_shift($@))])m4_dnl
])m4_dnl



m4_dnl
m4_dnl $1=type
m4_dnl $2=name
m4_dnl $3=methods: one or more of: get|get_mod|set|signal|handler|property|
property_def
m4_dnl $4=argtype: value|ref|constref|ptr|constptr
m4_define([CG_INLINE], [m4_dnl
CG_SETUP($@)m4_dnl
CG_OUTPUT_INLINES(CG_METHODS)m4_dnl
CG_CLEANUP])m4_dnl



m4_dnl
m4_dnl $1=type
m4_dnl $2=name
m4_dnl $3=methods: one or more of: get|get_mod|set|signal|handler|property|
property_def
m4_dnl $4=argtype: value|ref|constref|ptr|constptr
m4_define([CG_DEFINE], [m4_dnl
CG_SETUP($@)m4_dnl
CG_OUTPUT_DEFINITIONS(CG_METHODS)m4_dnl
CG_CLEANUP])m4_dnl


m4_dnl Set class
m4_define([CG_CLASS], [m4_define([CG_CLASSNAME], [$1])])m4_dnl
m4_dnl Output


m4_define([CG_OUTPUT], [m4_dnl
m4_undivert(CG_DIVERT_GET)m4_dnl
m4_undivert(CG_DIVERT_SET)m4_dnl
m4_undivert(CG_DIVERT_SIGNAL)m4_dnl
m4_undivert(CG_DIVERT_HANDLER)m4_dnl
m4_undivert(CG_DIVERT_PROPERTY)m4_dnl
m4_undivert(CG_DIVERT_PROPERTYDEF)m4_dnl

m4_undivert(CG_DIVERT_TIE)m4_dnl
])m4_dnl


m4_define([CG_OUTPUT_GET], [m4_undivert(CG_DIVERT_GET])


m4_define([CG_OUTPUT_SET], [m4_undivert(CG_DIVERT_SET)])


m4_define([CG_OUTPUT_SIGNAL], [m4_undivert(CG_DIVERT_SIGNAL)])


m4_define([CG_OUTPUT_HANDLER], [m4_undivert(CG_DIVERT_HANDLER)])


m4_define([CG_OUTPUT_PROPERTY], [m4_undivert(CG_DIVERT_PROPERTY)])


m4_define([CG_OUTPUT_PROPERTYDEF], & #91;m4_undivert(CG_DIVERT_PROPERTYDEF)])



m4_define([CG_OUTPUT_TIE], [m4_undivert(CG_DIVERT_TIE)])



m4_divert(0)m4_dnl
- --------

- --
Roger Leigh
Printing on GNU/Linux? http://gutenprint.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8+ <http://mailcrypt.sourceforge.net/>

iD8DBQFEBhpLVcFcaSW/ uEgRAif2AJ9O+Jbfa9ylNVtWh6N7Pmt8FnDaDgCd
G7AZ
GqvGFTDVQiHXNu+66HcfvbA=
=cXwM
-----END PGP SIGNATURE-----
billy

2006-03-03, 6:42 pm

Roger,
With the example of the m4 code you posted,I think I'll stick with
perl. I'm a contractor and time is most important. It would be nice to
have them pay for me to learn a new language
Thank you

Micah Cowan

2006-03-03, 6:43 pm

"billy" <bp1497@att.com> writes:

> Roger,
> With the example of the m4 code you posted,I think I'll stick with
> perl. I'm a contractor and time is most important. It would be nice to
> have them pay for me to learn a new language
> Thank you


From reading this thread, I get the sence that you don't realize that
m4 isn't a "programming language", at least not in the usual sense
(though it may well be Turing-complete). It's a preprocessing language
(macro language): specifically, it was the preprocessor for FORTRAN.

It isn't hard to learn (though you may feel otherwise from viewing
code: but the code's complexity is actually due to the language's
utter simplicity). It'd take you a day or two, probably. Add another
to learn some of the standard idioms.

Perl and m4 have pretty wildly different applications, for the most
part. m4 is great for writing shorthand in your source code for
/other/ languages (it is often used for this in C), and, well,
sendmail config files. It is not used to develop programs, it's used
to transform intermediary m4 code into a (usually) more verbose text
file.

BTW, the hello world application in m4:

Hello, world!

That's the complete source code. :-)

-Micah
billy

2006-03-03, 6:43 pm

BTW, the hello world application in m4:


Hello, world!


Gotta love it

Roger Leigh

2006-03-03, 8:47 pm

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

"billy" <bp1497@att.com> writes:

> Roger,
> With the example of the m4 code you posted,I think I'll stick with
> perl. I'm a contractor and time is most important. It would be nice to
> have them pay for me to learn a new language


That was a rather complex and ugly example, to be fair

It can be easy:

$ cat test.m4
define(foo, bar)
foo
bar
$ m4 test.m4

bar
bar
$

"define" defines a macro foo that expands to "bar", so every
subsequent instance of "foo" expands into "bar". This is basic search
and replace stuff. Macros can also take arguments and you can expand
alternative bits depending upon conditionals, etc..

$ cat test.m4
define(foo, bar)dnl
foo
bar
$ m4 test.m4
bar
bar

dnl means "discard all characters up to and including a newline",
otherwise the newline after the define is left.


You can make it as complex as you like. For example, see:
http://autoconf-archive.cryp.to/ac_path_lib.html

This expands into shell script containing embedded C source, but
you'll see it can be clean and well documented, as well as well
structured. However, the structure of each macro is the structure of
the programming language or text we are expanding into--not m4 itself.


Regards,
Roger

- --
Roger Leigh
Printing on GNU/Linux? http://gutenprint.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.8+ <http://mailcrypt.sourceforge.net/>

iD8DBQFECOOqVcFcaSW/ uEgRAjqWAJ9cDm8OSB5mcItVrHp+mIZyhy9otwCg
82Tp
dniD3OBwGP3Xuj0A80MA30A=
=627I
-----END PGP SIGNATURE-----
Sponsored Links






Free braindumps | Software forum | Database administration forum

Copyright 2003 - 2008 webservertalk.com