1. Configuring and Building the C++ Front End#
This chapter is an introduction to configuring and building the front end and the various tools that come with it. Bringing up the front end on a new platform typically can be done in a few hours, and if the platform is close enough to a system for which sample configurations are available (e.g., Linux, Windows, etc.) that initial process can be reduced to a matter of minutes.
The front end can be configured for a variety of uses. For example, it could be part of a compiler with a custom code generator, or a compiler with a portable C-generating back end (the latter is provided). Alternatively, it could be part of a source analysis tool (without a code generator) or of a source transformation/translation tool (using the supplied C/C++-generating back end). Some of the tools supplied with the front end will not be needed for some of these applications. For example, a source analysis tool is unlikely to need the supplied prelinker tool to perform automatic instantiations. The details of the build process are therefore likely going to depend on the application. However, the overall structure of the source code is simple enough that customizing the build process should be straightforward.
The source code implementing the front end and associated tools is written in C++11 (i.e., ISO/IEC 14882:2011) and can be compiled using relatively current C++ compilers. The front end has been compiled with g++ 4.8.1, clang 3.3, and Microsoft Visual Studio 2015 (build 19.00.24215.1). The front end does not explicitly throw or catch exceptions and does not use C++ features that would requite runtime type information (RTTI), so those features can be disabled when compiling the front end (for compilers that support that). (The sample run-time support library is written in C++ and (if needed) is normally compiled using the front end itself. When building on Microsoft Windows, a component is also available to read metadata in C++/CLI mode: This is written in C++ for the Microsoft C++ compiler.)
1.1. Directories and Files in a Release#
After unpacking a release, its top-level directory should contain the following directories and files:
Makefile |
In a Unix-like environment (including Windows-hosted environments like
Cygwin or MinGW), the
make utility can be used to build the front
end and its supporting tools and components. This top-level
Makefile runs the make tool in the various subdirectories as
needed. It is geared primarily toward building a compiler using the
C-generating back end along with the sample run-time support library.
A make process using this top-level Makefile may therefore
terminate with errors for other situations; in that case, the
Makefiles in the appropriate subdirectories (especially
misc/ and src/) are still likely to be useful. |
src/ |
The directory containing the source files of the C++ front end and its
optional components (such as the C- and C++-generating back ends).
This directory contains a subdirectory
disp/ used to build the
stand-alone IL display utility. In addition to source code, the
src/ directory also holds the Changes file, which describes
the various changes made to the front end in the current and previous
releases. Note that most of the source files have the .c suffix
that would normally indicate a C source file. Starting with the 6.0
release, these files contain C++ source code and must be compiled
using a C++ compiler (with the C++11 dialect). The original filenames
have been maintained to make patching files easier. If desired,
symbolic links can be added to accommodate build environments as
necessary. |
bin/ |
Initially, this directory contains a script
eccp that can be used
to run the front end much like typical C++ compilers in Unix-like
environments (such as CC and g++). See
“The eccp script” for details. Once the front end is built (in
the src/ directory), it can be moved here for invocation by
eccp (this is done automatically if the top-level Makefile is
used). |
sample_edg_eccp_config/ |
The
eccp script can be configured in various ways. This directory
contains sample configuration files for some popular Unix-like
operating systems (Linux, MacOS X, and Solaris). It also includes a
script make_g++_incl_paths (to be run from the lib/ directory)
to establish the location of g++‘s header files (in cases where
eccp should rely on a native g++ installation for system and
standard header files). |
include/ |
This directory contains prototype implementations for a few standard
C++ header files that are closely tied to the compiler’s internals.
(For example, the contents of the
<typeinfo> header must match the
compiler’s understanding of the std::type_info type.) |
lib_src/ |
This directory contains C++ source code implementing a minimal C++
run-time support library (in support of C++ features like exception
handling, the
dynamic_cast operator, and operator new). The
library also includes support for certain extensions to the C89
language (like operations on complex floating-point types and support
for variable-length arrays). All of this code is primarily meant for
demonstration purposes, and is probably not suitable for end-user
products: It is very portable, but not very efficient. It is usually
not needed for non-compiler applications such as source analysis or
source-to-source translation. This directory also contains a
Changes file describing the history of the run-time support
library. |
lib/ |
Initially, this directory only contains a file
predefined_macros.txt. This file is read by the front end to
predefine certain macros. It is typically used to define macros that
are defined by compilers being emulated (see
make_predef_macro_table and make_win_predef_macro_table.c for
utilities that automatically generate a set of predefined macros for
GNU and Microsoft compilers, respectively). Once the run-time support
library is built (in the lib_src/ directory), it can be moved here
so the eccp script can find it (this is done automatically if the
top-level Makefile is used). Note that this directory is only
used when an unnamed “legacy” target configuration is specified – see
lib_target/ below for cases where a named target
configuration is used. |
lib_target/ |
Target-specific version of the
lib/ directory described above
used when the “--target target” command-line option is
specified. This directory can have the same
predefined_macros.txt and libC.a files as lib/, or can
be different as required by the specific target. If a
target-specific version of libC.a is required, it must be
built manually (see lib_src/Makefile). |
misc/ |
This directory contains sources for four utility programs (and a
|
util/ |
This directory contains sources for three utility programs (and a
|
doc/ |
This directory contains a PDF version of this document (
plm.pdf). |
README |
A plain text file summarizing some of the information in this chapter.
|
1.2. Configuring the Front End#
A large number of behaviors of the front end can be configured by appropriately defining various configuration macros. These macros can affect which components of the front end are enabled, which dialects are supported, what host and target platform characteristics are assumed, and so forth. See lang_feat.h, host_envir.h, targ_def.h, and target.h below for information about where all the macros are documented.
Beginning with version 4.10.1 of the front end, a facility to provide for
run-time selection of a target configuration (through the use of the
--target command-line option) is provided. To support this run-time
target-configuration feature, a number of the configuration macros have
been designated as “target-specific”. See
Target-Specific Configuration for more information.
1.2.1. The defines.h File#
It is highly recommended that the front end be configured by defining the
appropriate macros in the src/defines.h file. Occasionally, it may be
expedient to set the macros directly through src/Makefile or a similar
build-system mechanism (e.g., to enable debugging facilities), but modifying
other front end sources to set the configuration macros is not a recommended
option.
Sample configuration files are provided in the src/ directory for Linux,
MacOS X, Solaris, and Windows (defines.h.linux, defines.h.macosx,
defines.h.solaris, and defines.h.win32, respectively). These are
recommended starting points when building the front end on these platforms: For
example, to build the front end on MacOS X, one can start by copying
src/defines.h.macosx to src/defines.h.
A partial configuration file src/defines.h.proto is also provided: It
contains the macros needed to enable the modern IA-64 ABI (also called the
Itanium ABI), but it must be complemented by additional target characteristics
(which can be obtained by running the dettarg utility described next).
1.2.2. The dettarg Utility#
File misc/dettarg.c is a simple C++ program that can be compiled, linked,
and run on a system for which the compiler is targeted to determine some basic
characteristics (like endianness, size and alignment of fundamental types, and
so forth) of that target platform. The output produced by dettarg is in a
form suitable for addition to the src/defines.h file.
1.2.3. lang_feat.h, host_envir.h, targ_def.h, and target.h#
A typical src/defines.h file will not explicitly set all the configuration
macros available in the front end. Instead, most macros are just left to their
default values. These defaults are specified in four header files. Perhaps
more importantly, these header files are also the place where all the
configuration macros are documented (in comments preceding the directives
determining the default values). The header files are as follows:
src/lang_feat.h |
Configuration macros controlling language features. Some macros
control a single language feature detail, whereas others control whole
dialects.
|
src/host_envir.h |
Configuration macros that determine characteristics of the host
platform (the platform on which the front end runs).
|
src/targ_def.hsrc/target.h |
Configuration macros describing characteristics of the target platform
(the platform for which code must be generated). Many of these macros
have names that begin with
TARG_. Characteristics that are
entirely fixed at the time the front end is built are normally
documented in targ_def.h, whereas target.h describes target
characteristics that can be overridden for every invocation of the
front end. |
These descriptions are generally correct, but occasionally a configuration
macro may need to be placed in a header that doesn’t quite match that macro’s
function. For example, targ_def.h contains some macros that would more
naturally belong to lang_feat.h, but the default value of the macro depends
on a target platform characteristic.
Note that these files should not be modified to set configuration options.
Instead, the appropriate macros should be defined in src/defines.h or
perhaps in a Makefile or similar build system tool.
1.2.4. basics.h and Build Environment Configuration#
The front end is written in portable C++11 (except for one file in the
Microsoft dialect if the capability of reading Microsoft metadata for
C++/CLI is needed). The basics.h header adds abstractions to allow
most of the remainder of the front end source code to be written without
concern for variations in system headers. The build environment type can
often be determined by the preprocessor tests in basics.h, but when
that is not the case, one should define one of the following build
environment macros (on the command-line or in src/defines.h):
__ANSIC__ (for ANSI C; also used for Borland and Microsoft C under
MS-DOS and Windows), __SYSV__ (for System V), __BSD__ (for Berkeley
4.n), __VMS__ (for VAX/VMS C; this will cause __SYSV__ to be
defined, but the __VMS__ flag will control some minor variations from
System V).
Some ANSI library functions do not exist in all system libraries. This problem
is handled by remapping such function calls (via macros) to functions that do
exist. For example, traditional Berkeley UNIX does not have memcpy, but
does have bcopy; the front end source is written using calls to memcpy,
but when it is compiled with the __BSD__ flag set, a macro memcpy
transforms those calls into calls to bcopy. Another function of the build
environment macros is controlling inclusion of appropriate header files. Even
when identical functions exist on different host systems, they are sometimes
defined by different header files (e.g., Berkeley systems use <strings.h>
instead of the ANSI/System V <string.h>). basics.h includes the
appropriate definitions for the most common functions (standard I/O, string and
block operations, and character typing); any other required headers are
included only in those source files that need them, with appropriate
conditional compilation surrounding the #includes.
Very occasionally, the macro definitions in basics.h must be modified
directly (i.e., by editing basics.h). Specifically, when __ANSIC__ is
not set, some #defines in basics.h must establish values for about a
dozen of the most useful values (specifically, CHAR_BIT, CHAR_MIN,
CHAR_MAX, UCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX,
LONG_MIN, and ULONG_MAX). These should be set to proper values for the
host. sizeof_t should also be defined as the integral type to be used for
sizes of things. Usually this is the same as size_t, but it might be
different if size_t is too small (e.g., 16 bits). These values cannot be
set in defines.h or on the compilation command line.
Finally, basics.h also determines the default values of some macros that
control the presence of code aiding in the development of the front end (e.g.,
DEBUG for debugging aids and CHECKING for internal consistency checks).
The front end requires a minimal C++ standard library. Prior to release 6.0,
the front end was written in C and used various host C standard library
functions (e.g., for file I/O). When switching to C++, it was decided not to
use the additional portions of the C++ standard library that became available
(e.g., std::string) as this would add a burden to our customers and would
require testing against many versions of the C++ standard library. Instead, a
small subset of library-like utility functions was developed for the front end
(in util.h). As a result, the portion of a C++ standard library that the
front end requires is about the same as that provided by a C standard library.
1.2.5. Commonly-used Configuration Macros#
The following subsections describe a selection of macros that commonly appear
in src/defines.h. This list is not meant to be exhaustive. Many (but not
all) configuration macros are used to initialize global variables with a
similar name, and it is the value of the variable that controls a particular
behavior. For example, GCC_IS_GENERATED_CODE_TARGET (described below)
initializes the global variable gcc_is_generated_code_target. This allows
particular behaviors to be controlled at run time (via the command line or via
custom code additions).
Note that none of the configuration macros described below are
“target-specific” (so, for example, there can’t be one target configuration
where DO_IL_LOWERING is TRUE and another where it is FALSE).
1.2.5.1. Optional Components#
BACK_END_SHOULD_BE_CALLED |
TRUE if a back end should be called (the call is to a function
back_end). |
DO_IL_LOWERING |
TRUE if IL lowering (rewriting C++-specific constructs in the
intermediate language in C form) should be done.
|
BACK_END_IS_C_GEN_BE |
TRUE if the C-generating back end should be used. If FALSE, some
other back end must be supplied or
BACK_END_SHOULD_BE_CALLED must
be FALSE. The C-generating back end takes the lowered IL for a
translation unit and generates a C source file suitable for
compilation to binary code by a native C compiler. |
BACK_END_IS_CP_GEN_BE |
TRUE if the C++/C-generating back end should be used. If FALSE, some
other back end must be supplied or
BACK_END_SHOULD_BE_CALLED must
be FALSE. The C++/C-generating back end is intended for
source-to-source transformation applications. It takes the unlowered
IL for a translation unit and generates a source file that is similar
to the original C or C++ input. |
MINIMAL_INLINING |
TRUE if minimal inlining of function calls should be done during IL
lowering. This option is intended mostly for use with the
C-generating back end, and is limited to inlining calls to very simple
functions that are defined inline in the source.
|
1.2.5.2. Support for Source Language Dialects#
GNU_EXTENSIONS_ALLOWEDDEFAULT_GNU_COMPATIBILITY |
Control whether compatibility with GNU’s
gcc and g++ compilers
should be enabled, either by default or only when the --gcc or
--g++ command-line options are specified. |
MICROSOFT_EXTENSIONS_ALLOWEDDEFAULT_MICROSOFT_COMPATIBILITY |
Control whether compatibility with Microsoft’s C and C++ compilers
should be enabled, either by default or only when the
--microsoft
command-line option is specified. |
SUN_EXTENSIONS_ALLOWEDDEFAULT_SUN_COMPATIBILITY |
Control whether compatibility with Sun CC should be enabled, either by
default or only when the
--sun command-line option is specified. |
Setting an …_ALLOWED macro to TRUE makes the corresponding
DEFAULT_… macro TRUE by default. If the front end is configured to
support multiple dialects, the DEFAULT_… macros must be set explicitly
to avoid selecting more than one dialect as the default.
CPPCLI_ENABLING_POSSIBLE |
Control whether a mode compatible with Microsoft’s C++/CLI extensions
should be available through the command-line option
--cppcli.
Setting this option to TRUE requires that
MICROSOFT_EXTENSIONS_ALLOWED also be TRUE. |
DEFAULT_CPPCLI_ENABLED |
TRUE if C++/CLI extensions should be enabled by default when Microsoft
extensions are enabled.
|
1.2.5.3. IL Features#
EXTRA_SOURCE_POSITIONS_IN_IL |
TRUE if certain additional IL entries, besides those that already have
a_source_correspondence fields, should contain source position
information. For example, expression nodes will record the starting
and ending position of the corresponding expression, as well as the
position of that expression’s top-level operator. Note that this can
increase the size of the IL substantially. |
EXPR_RANGE_MODIFIERS_IN_IL |
TRUE to extend the tracking of source ranges for expressions by
including position information for operators that generally do not
appear in the IL, such as
*, &, and (). |
RECORD_MACROS_IN_ILFULLY_RESOLVED_MACRO_POSITIONSMACRO_INVOCATION_TREE_IN_IL |
Indicate whether extra information should be recorded in the IL to
track macros and their expansions. Setting either of the latter two
configuration macros to TRUE can increase the size of the IL
substantially.
|
PROTOTYPE_INSTANTIATIONS_IN_IL |
TRUE if prototype template instantiations (i.e., the parsed generic
form of templates) should be recorded in the main IL tree.
|
1.2.5.4. Target Platform Options#
Note that although these configuration macros deal with issues related to the target, they are not considered “target-specific” (because these values cannot differ between target configurations).
IA64_ABI |
Controls whether the IA-64 ABI standard is used for code generation
and object layout. This is a “modern” C++ object layout (unlike the
cfront layout), and is a good starting point even on architectures
other than IA-64 (Itanium). This ABI is used by many versions of g++
(3.2 and later). For a complete specification, see
www.codesourcery.com/cxx-abi. See also other macro names
beginning with IA64_ABI, some of which enable compatibility with
the ARM EABI variant of the IA64_ABI. If IA64_ABI is set to
FALSE (or 0), a cfront-like ABI is used instead. |
DEFAULT_GNU_ABI_VERSIONDEFAULT_EMULATE_GNU_ABI_BUGS |
Control the emulation of the GNU variant of the IA-64 ABI.
|
GCC_IS_GENERATED_CODE_TARGETGNU_TARGET_VERSION_NUMBERMSVC_IS_GENERATED_CODE_TARGETMSVC_TARGET_VERSION_NUMBERSUN_IS_GENERATED_CODE_TARGETSUN_TARGET_VERSION_NUMBER |
Control whether the code generated by the C- or C++-generating back
end should target a specific GNU, Microsoft, or Sun compiler. This is
information is used to avoid limitations of those compilers and to
exploit extensions provided by those compilers.
|
CP_GEN_BE_TARGET_MATCHES_SOURCE_DIALECT |
TRUE if the C++-generating back end should generate code that matches
the dialect selected for the front end. (E.g., if the front end is
set to parse GNU code, the back end can generate GNU
__attribute
constructs, whereas if the front end is set to accept Microsoft
extensions, the back end might generate __declspec specifiers.) |
1.2.5.5. Front End Behaviors#
MAKE_FRONT_END_CALLABLE |
TRUE if, instead of having its own main program, the front end is to
be linked as part of some other main program. When this flag is set,
the
EDG_MAIN macro provides the name of the main entry point into
the front end.The front end can then be called repeatedly by the same
process (each call reinitializes the front end’s internal state). |
COMPILE_MULTIPLE_SOURCE_FILES |
Indicates that the front end should be capable of compiling a list of
source files in a single invocation.
|
IL_SHOULD_BE_WRITTEN_TO_FILE |
TRUE if the intermediate language should be written to a file; FALSE
if the intermediate language is passed in memory to the back end
(assuming
BACK_END_SHOULD_BE_CALLED is TRUE). |
USING_DRIVER |
Indicates that the front end is being run from a driver program.
Setting this flag suppresses termination messages (like
“
Compilation terminated.”) written to the error output file
because it is expected that the driver will write those. |
MULTIBYTE_CHARS_IN_SOURCE_SUPPORTED |
TRUE if multibyte character sequences (e.g., like Unicode UTF-8 or
those in the Japanese SJIS encoding) are supported in comments,
string literals, identifiers, and character constants.
|
USE_OWN_SJIS_MULTIBYTE_CHAR_PROCESSING |
TRUE if, instead of the routines in the standard C library (e.g.,
mblen), custom routines in host_envir.c should be used to deal
with Japanese SJIS multibyte characters in source code. |
LOCALE_TO_SET_WHEN_MULTIBYTE_CHARS_ENABLED |
Indicates the locale to be established by a call to
setlocale to
get the desired processing of multibyte characters from the C library
while reading the source code. |
UNICODE_SOURCE_SUPPORTED |
TRUE if the multibyte character set to be supported is Unicode encoded
as UTF-8. UTF-16 is also accepted, and is translated to UTF-8
immediately on input.
|
1.2.5.6. Development Aids#
DEBUG |
Enables additional code in the front end to simplify debugging. This
includes flow/event tracing options, routines that can be called from
a debugger to examine the IL, and an option to output the settings of
the configuration macros.
|
CHECKING |
Enables inexpensive internal consistency checking. Recommended even
in production builds.
|
EXPENSIVE_CHECKING |
Enables more expensive internal consistency checking. (Not generally
recommended for production builds.)
|
WRITE_CPPCLI_PORTABLE_ASSEMBLIES |
When TRUE, this enables an internal command-line option “
--set_flag
generate_portable_assemblies” that causes a front end built with
support for C++/CLI (for Microsoft Windows) to write out all
assemblies used in the compilation (likely including mscorlib.dll)
to be written in the current directory in a format that is readable on
non-Windows platforms (i.e., with a front end not built with
EDG_WIN32 set to TRUE). Since the assemblies are written in the
current directory with their original file name (e.g.,
“mscorlib.dll”), care should be taken that no required assemblies
are in the current directory when the front end is invoked in this
way. |
1.2.6. Target-Specific Configuration#
A target configuration is defined by giving appropriate values to a set of
configuration macros (dubbed the target-specific configuration macros).
Multiple target configurations can be specified when the front end is built;
the --target command-line option is used to select a non-default target
configuration when the front end is invoked. The --dump_legacy_as_target
command-line option can be used to display the set of target-configuration
macros.
Each target-specific configuration macro has a “legacy” version, i.e., one
without any target-specific suffix, as well as a version for each target
configuration that is specified when the front end is built. Non-legacy
configuration macro names are formed by appending an underscore and the target
configuration name to the legacy configuration macro name. For example, the
legacy macro TARG_LITTLE_ENDIAN would have a corresponding
TARG_LITTLE_ENDIAN_win32 configuration macro for the win32 target
configuration.
By default, the legacy configuration has no name, but one may be specified by
setting LEGACY_TARGET_CONFIGUATION_NAME to the desired name. The default
target configuration can be specified by giving its name as the definition of
the DEFAULT_TARGET_CONFIGURATION_NAME configuration macro; otherwise, the
legacy target configuration will be used as the default.
Note that specifying a named target configuration (either explicitly or through
defaults) requires that an $EDG_BASE/lib_target/ directory be
present at run time. Having target-specific $EDG_BASE/lib_target/ directories allows each target configuration to have different predefined
macros (e.g., to define _M_IX86 in one and _M_X64 in another).
A legacy configuration can be configured manually (by specifying values for
each target-specific macro), or automatically (by using the dettarg tool
and defaults that many configuration macros have). The
--dump_configuration command-line option provides a convenient display of
all configuration macros and their settings.
A non-legacy target configuration is most easily generated as a derivative from
an existing legacy target configuration using the --dump_legacy_as_target
command-line option. This option takes a target configuration name and
generates a list of the target-specific macro names for the given target
configuration name along with the values of the legacy configuration. This
file (after verifying that TARGET_CONFIGURATION_number is unique) can
then be included in defines.h as the basis for a new target configuration.
Additional target configurations can be generated from different legacy
configurations in the same manner, or by using an existing target configuration
as a template (and changing the target configuration name in each macro, along
with the TARGET_CONFIGURATION_number). Note that all target-specific
configurations must share the same non-target-specific configuration, so for
instance, it’s not possible to have an IA-64 ABI target configuration and a
Cfront target configuration in the same front end configuration (because
IA64_ABI is not a target-specific configuration macro and must have the
same value across all target configurations).
Note that it is inadvisable to use a target-specific global variable as the value for a target-specific configuration macro. For example:
#define TARG_IA64_VTABLE_ENTRY_INT_KIND targ_ptrdiff_t_int_kind
is subject to race conditions (because targ_ptrdiff_t_int_kind may or may
not have been initialized before its value is used to set
targ_ia64_vtable_entry_int_kind). The following will work as expected:
#define TARG_IA64_VTABLE_ENTRY_INT_KIND TARG_PTRDIFF_T_INT_KIND
An important aspect of this architecture is that each legacy configuration macro has an associated global variable whose value is set at initialization time to the value of the (legacy or per-target) configuration macro for the selected target. Because of this, it is imperative that user modifications to the front end use the run-time value of global variables rather than the compile-time values of legacy configuration macros.
1.2.7. Replaceable Code#
Occasionally, some customizations are needed that cannot simply be expressed
through configuration macros. Those may require instead that various routines
be replaced with custom code. The following files in src/ are written with
such modifications in mind:
fixed_pt.c |
Routines implementing operations on fixed-point values (only supported
in some configurations).
|
float_pt.c |
Routines implementing operations on floating-point values.
|
host_envir.c |
Includes routines dealing with operations on files and directories.
Signal handlers can also be set up there.
|
sys_predef.c |
Routines to predefine platform-specific entities (macros, types,
routines, etc.)
|
1.3. Building the Front End#
1.3.1. Using the Top-Level Makefile#
Assuming a Unix-like environment, a complete demonstration compiler can be configured and built using a sequence of shell commands like the one shown below (for a typical Linux platform, but other Unix-like environments are similar). The sequence assumes that the current directory is the top-level directory of a freshly unpacked release.
cp sample_edg_eccp_config/edg_eccp_config.linux edg_eccp_config
cp src/defines.h.linux src/defines.h
cd lib
../sample_edg_eccp_config/make_g++_incl_paths
../misc/make_predef_macro_table
cd ..
export EDG_BASE=`pwd` # or setenv EDG_BASE `pwd`
make
This builds a front end with a C-generating back end, along with a run-time
support library and helper tools such as the prelinker and demangler. The
entire toolset can be driven with the eccp script (see
“The eccp script”).
1.3.2. Building the Front End Only#
In an environment with a Unix-like make utility, the front end can be
compiled and linked by running
make edgcpfe
in the src/ directory (after constructing an appropriate defines.h file
and editing src/Makefile to select the desired compiler and compiler
options for building the front end). This can be useful to update the front
end for modifications after building the complete tool set, or when only the
front end program itself is desired. If make is not available, the front
end can be built using the following manual steps.
- Configure the
defines.hfile. For example, under Windows the following is a useful starting point:copy src\defines.h.win32 src\defines.h - In the
misc/directory, compile and link themk_errinfoprogram into amk_errinfoexecutable file. For example, using a Windows command line and the Microsoft C++ compiler:cd misc cl /TP /I..\src mk_errinfo.c cd ..
See mk_errinfo for additional information aboutmk_errinfoand the format of its input files. - In the
src/directory, translate the diagnostic messages using themk_errinfoprogram that was built in the previous step. For example, using a Windows command linecd src ..\misc\mk_errinfo error_msg.txt error_tag.txt err_codes.h err_data.h
- Still in the
src/directory, compile and link all the.cand.cppfiles. For example:cl /TP /EHsc /Feedgcpfe.exe *.c *.cpp /link mscoree.lib oleaut32.lib
1.3.3. Building Support for C++/CLI and C++/CX Modes#
C++/CLI is a Microsoft extension to C++ that simplifies writing C++-like programs for Microsoft’s “.NET” environment. It is formally specified by the ECMA standard ECMA-372. The front end can support this extension, provided it is built on a sufficiently recent Microsoft Windows platform with a compiler that is sufficiently compatible with Microsoft’s “Visual C++” compiler. This support is currently limited to producing high-level IL. The C++-generating back end can consume this IL (and render the C++/CLI constructs it describes), but lowering and the C-generating back end are not available in C++/CLI mode.
C++/CX is a Microsoft extension to C++ similar to C++/CLI, but it targets the “Windows Runtime” (WinRT) platform instead of the “.NET” environment. Unlike C++/CLI, there is no formal document specifying this extension. The front end can also support C++/CX, with the same caveats as those mentioned for C++/CLI support (in particular, IL lowering is not available for C++/CX mode).
To include support for C++/CLI and/or C++/CX the configuration macros
CPPCLI_ENABLING_POSSIBLE and/or CPPCX_ENABLING_POSSIBLE (respectively)
must be set to TRUE. (The macros MICROSOFT_EXTENSIONS_ALLOWED and
EDG_WIN32 must also be TRUE when building such configurations.) In addition
to compiling the C files constituting the front end proper (as explained
above), support for C++/CLI and/or C++/CX requires that the C++ source file
ms_metadata.cpp be compiled as C++ and the resulting object file must be
added to the set of files linked into the final front end executable (or
library). The system libraries mscoree.lib and oleaut32.lib are then
also required in the final executable.
Compiling ms_metadata.cpp requires Visual C++ 2012 or later (or a C++
compiler and libraries that are sufficiently compatible with that). The free
“Express” version of Visual C++ is not sufficient because it doesn’t include
the ATLMFC library, which ms_metadata.cpp depends on.
1.3.4. Building and Using the IL Display Program#
For educational and debugging purposes, the front end comes with a utility
named edgcpdisp that reads a file containing the IL produced when the front
end compiles one or more source files and displays it in a human-readable form.
(In order to use this facility, of course, the front end must be configured to
write an IL file, i.e., IL_SHOULD_BE_WRITTEN_TO_FILE must be set to TRUE in
defines.h or in src/Makefile.)
Because the IL file written by the front end is essentially a binary dump of
the IL data structures, it is necessary for the front end and edgcpdisp to
be built on the same platform and using the same configuration options. (Many
of the IL data structures contain fields that are present only in certain
configurations.)
In an environment with a Unix-like make utility, edgcpdisp is
automatically built (with a configuration that correctly matches that of the
front end) when make is run for the default target in either the top-level
or src/directory. It can also be built separately by using make in
the src/disp/directory.
If make is not available, edgcpdisp can be built after the front end is
built (as described in the preceding section) in the src/directory by
compiling a subset of the source files with STANDALONE_IL_DISPLAY set to
TRUE. For example, on a Windows platform using the Microsoft C++ compiler, the
command would be (all on one line):
cl /TP /Feedgcpdisp.exe -DSTANDALONE_IL_DISPLAY const_ints.c debug.c \
error.c fixed_pt.c float_pt.c host_envir.c il.c il_display.c il_read.c \
il_to_str.c il_walk.c mem_manage.c target.c types.c fe_init.c
Displaying the IL for a source file x.cpp can be accomplished with the
following commands:
edgcpfe --output x.cil x.cpp
edgcpdisp x.cil
(In configurations that do IL lowering, x.cil will contain the lowered IL.
To view the unlowered IL, see the --no_il_lowering front-end command-line
option described in the next chapter.)
1.4. Driving the Front End#
For many applications, it is useful to invoke the front end through another
“driver” program. One such driver is the bin/eccp script that is part of
every release. Another is the edgcc program that can be downloaded
separately from the EDG download site.
1.4.1. The eccp script#
The bin/ directory contains a (Bourne) shell script eccp that
allows the front end to be used much like most Unix-hosted compilers. It
invokes the front end – which must be configured with the C-generating back
end – with various default options, and then compiles any generated C files
through a “native” C compiler (e.g., the GNU gcc compiler) and a native
linker. The script accepts Unix-like compiler options (such as -c,
-o, -O, -g, -I, -L, and -l) and also passes through
most of the options handled by the front end proper (see Command Line).
The script can be moved anywhere, but it normally looks for various components
(the front end, the prelinker, etc.) under a directory designated by the
environment variable EDG_BASE. The eccp script can be edited to set a
default substitute value for the EDG_BASE variable. Normally, the value of
EDG_BASE is the top level directory of a fully-built release tree (although
the src/ and lib_src/ directories are not used by eccp). eccp
will start by setting various environment variables by executing a script
$EDG_BASE/edg_eccp_config. Sample scripts for various platforms are
provided in the sample_edg_eccp_config/ directory. Two environment
variables commonly customized in the edg_eccp_config script are
EDG_DEFAULT_DEFINES (to add options like -D__unix__) and
EDG_C_TO_OBJ_COMPILER (to establish which “native” compiler to use; e.g.,
gcc).
eccp may also invoke the prelinker (util/edg_prelink) to automatically
instantiate templates (and, with some front end configurations, inline
functions that need an out-of-line copy). See
Automatic Instantiation for notes on this process. The script will
also run util/edg_munch if needed, and filter linker errors through
util/edg_decode.
See “Utility Programs” for more information on the utility programs
edg_prelink, edg_munch, and edg_decode used by the eccp script.
1.4.2. The edgcc Driver for Windows#
A Windows program implementing a subset of eccp‘s functionality can be
downloaded from the EDG download site. The file to download is
nt_util.zip. In addition to source code for the driver program edgcc,
it also contains source code for a Windows-hosted prelinker (pl_nm) and
munch-like program (munch_nm).
The plain text file src/msinfo contains additional notes for running the
front end in the Windows environment.
1.5. Configuring and Building the Run-Time Support Library#
Source code for a sample run-time support library is provided in the
lib_src/ directory. This library is meant to be built using the front end
(i.e., a compiler incorporating the EDG front end). The library is useful for
demonstration and debugging purposes. However, it is normally not suitable for
production compilers because it is written in portable C++ that cannot take
advantage of more efficient platform-specific mechanisms (e.g., to implement
exception handling).
Similarly to the front end, the library can be configured through macro
definitions placed in lib_src/defines.h. Typically, however, few or no
macros need to be defined because the --build_runtime option to the front
end (used to build this library) causes most or all required macros to be
predeclared.
The macros that might need manual configuration are documented in
lib_src/config.h.
When using multiple target configurations, a version of the run-time support
library must be built for each target configuration and installed in the
appropriate lib_target/ directory. See lib_src/Makefile for
directions to build target-specific versions of the library.