On Sun, Jan 17, 2016 at 4:11 AM, anatoly techtonik <techto...@gmail.com> wrote:
> And actually I don't understand what "a tool to help you configure
> projects" really means, because I am not familiar with autoconf
> (that's why I asked the question in the first place). So I see that C
> files already have #define mechanism inside, but it looks like C
> compilers can not agree what #define's to set and what do they mean.
> That's why users need to create #defines themselves and define the
> meaning for them. Am I right?
>
> Is there any attempt to define standard set for those #define's and
> their meaning across compilers?

If you're just starting out, it's not unusual to set compiler and
platform specific functionality using defines built into the compiler.
However, most experienced C/C++ developers consider it bad practice to
do so.  Instead, they create their own defines to help specify which
platforms should use subsets of code that may not be portable.  Why go
to all this trouble and create defines independent to the compiler and
platform?  Take a look at some real world examples.  What happens when
you try to build a library using X11 on Windows, but it hard codes
Win32 header files using the compiler's flag to check if you're on a
Windows platform.  You have to go through and fix every define,
because you only want the X11 headers, not the Win32 headers.  Cygwin
went so far as to remove the Windows define from their compiler so
they wouldn't have the issue.  However, if you're using X11 on a
Windows compiler other than Cygwin and the library or application uses
a builtin define, you're stuck fixing every instance of it.  I often
find myself going in and fixing defines because someone assumed
functionality was or wasn't available based on a compiler flag and my
compiler doesn't behave the way they assumed.  That's typically why
using built-in compiler defines to determine what code to use is not
considered the best practice.  What about when a compiler doesn't
support a feature in one version, but does in a later version?  Then
not only do you need to check the compiler flags for what operating
system and what compiler, but also what versions work and what
versions don't with a particular feature.  What happens when you need
to know the sizeof a particular type on a particular system?  Do you
assume you know what it is based on compiler and platform?  How do you
know if you're on a 32 or 64 bit system?  Do you look for yet more
compiler specific defines?  What if there aren't any?  C libraries
like musl went to great lengths not to have any compiler specific
defines to let you know that you're working with musl in place of
something like glibc or uclibc.  The developer wanted to be able to
add new features in later versions and discourage developers from
hard-coding what works based on compiler specific defines.  Things
also get complicated if you're building with a cross-compiler.  If you
check what platform you're on according to the compiler, it might tell
you Linux, but you may be building for Windows or an embedded system
with DOS or some other platform.

If you're familiar with a language like JavaScript, you'll find
JavaScript developers solve the issue of platform specific code by
using a runtime check to see whether functionality is available.  Some
developers have taken a similar approach with C/C++.  AT&T came up
with one configure/build system that does runtime time checks for
functionality.  Typically however, the most widely adopted methods for
checking functionality in C/C++ are systems such as autoconf and
cmake.  They creates small programs to run to see if a feature is
available or if it will fail, to check the size of types, to check
what flags work if a library is available, etc.  So basically it's
doing a runtime check.  The information gathered from these runtime
checks can be used to create defines or select what code is used when
the program is built.  So build systems for most C/C++ programs check
for runtime functionality during the build instead of having the
programs check when they're run.  It's usually much faster for a
program to do the check ahead of time and use the information in the
compile than to try to check everything dynamically at runtime.  It's
also easier for the developer if the build tool simply checks if the
code works or not on a platform rather than the developer trying to
code in every possible combination of which compiler specific flags
might be available and in what combination to determine how to do with
code that might not be portable.

It would be much simpler if developers stuck with code that was
portable to all systems, but in practice, this usually only happens
for very small sample programs.  Even command line tools like many of
the common GNU command line utilities (find, ls, etc.) use a lot of
platform specific code that's not part of the official C language
specifications.  There are several extensions to the C language such
as the POSIX standards.  Many of the POSIX standards are not part of
the official C standards.  They're typically a superset of the C
standards.  They are not necessarily portable to non-POSIX platforms.

> Then tools like autoconf are used to detect which #define is correct
> for specific system and set its value accordingly. Right? This is made
> by perl script named ./configure. Right? What is the role of cDetect
> then? Is it a C program that does the job of Perl ./configure?

configure is typically a bash script.  Some applications create their
own configure scripts using other languages like Perl or TCL, but
these projects probably aren't using the standard GNU autoconf
program.  The GNU configure system uses several languages just to
build a basic C or C++ program including m4 and Perl.  If you're
attempting to build libraries/applications on a minimal system or from
scratch, ideally, it would be nice to just require one language to do
so.

Using CDetect or other configure programs lets you determine what
features will compile successfully and what settings to use before you
actually build a program.  Most build systems also use some type of
make program to do the actual compile steps once the build system
figures out how best to build the application or library on that
particular system.

So that's more than most people probably want to know about the
rationale behind build systems for compiled programs.  However, if you
don't understand what others have done and where other systems have
worked well or failed, you're bound to make the same mistakes all over
again.

Sincerely,
Laura

Reply via email to