User:Gso321/GCC/Frontend/Hello world
Before starting, the following is required: dev-vcs/git, internet connection, and around 3 GB of free disk space. The example language name will be "Opus". Any references to any language with the name "Opus" are purely coincidental.
Setting GCC up
This grabs the GCC source code into gcc-src directory, which may take a while depending on the speed of the system’s internet speed. Then make the gcc-build directory, which is where GCC build will happen.
Make sure GCC has requirements to compile itself:
user $
./contrib/download_prerequisites
Add the opus directory and change into gcc/opus directory for the language (This is the main directory for an language):
user $
mkdir gcc/opus
user $
cd gcc/opus
Required files
When creating a language, GCC expects some files to be presented. In this example, it would be config-lang.in
, Make-lang.in
, lang-specs.h
, opus-lang.cc
, and opusspec.cc
.
config-lang.in
language="opus"
compilers="opus1\$(exeext)"
build_by_default="no"
gtfiles="\$(srcdir)/opus/opus-lang.cc"
See this for more information.
The language
specifies the name of language as it would appear in $(LANGUAGES). The compilers
specifies the internal language compiler to use in $(COMPILERS). The \$(exeext) expands to .exe when using Windows OS, meant to make it executable for the Windows OS. The build_by_default
with "no" means GCC needs to have —-enable-languages=opus
in order for GCC to compile opus files. gtfiles
relates to this link.
lang-specs.h
{".opus", "@opus", 0, 1, 0},
{"@opus",
"opus1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}", 0, 1,
0},
In this lang-specs.h header file, it directs files ending with .opus in line 1 to the opus1 compiler via %i (%i, like C's printf, is replaced with the .opus files) in line 2.
Make-lang.in
GCCOPUS_INSTALL_NAME := $(shell echo gccopus|sed '$(program_transform_name)')
GCCOPUS_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccopus|sed '$(program_transform_name)')
opus: opus1$(exeext)
opus.serial = opus1$(exeext)
.PHONY: opus
# Driver
GCCOPUS_OBJS = \
$(GCC_OBJS) \
opus/opusspec.o \
$(END)
gccopus$(exeext): $(GCCOPUS_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS)
+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
$(GCCOPUS_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \
$(EXTRA_GCC_LIBS) $(LIBS)
# The compiler proper
opus_OBJS = \
opus/opus-lang.o \
$(END)
opus1$(exeext): attribs.o $(opus_OBJS) $(BACKEND) $(LIBDEPS) $(opus.prev)
@$(call LINK_PROGRESS,$(INDEX.opus),start)
+$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
attribs.o $(opus_OBJS) $(BACKEND) $(LIBS) $(BACKENDLIBS)
@$(call LINK_PROGRESS,$(INDEX.opus),end)
opus.all.cross:
opus.start.encap: gccopus$(exeext)
opus.rest.encap:
opus.install-common: installdirs
-rm -f $(DESTDIR)$(bindir)/$(GCCOPUS_INSTALL_NAME)$(exeext)
$(INSTALL_PROGRAM) gccopus$(exeext) $(DESTDIR)$(bindir)/$(GCCOPUS_INSTALL_NAME)$(exeext)
rm -f $(DESTDIR)$(bindir)/$(GCCOPUS_TARGET_INSTALL_NAME)$(exeext); \
( cd $(DESTDIR)$(bindir) && \
$(LN) $(GCCOPUS_INSTALL_NAME)$(exeext) $(GCCOPUS_TARGET_INSTALL_NAME)$(exeext) ); \
# Required goals, they still do nothing
opus.install-man:
opus.install-info:
opus.install-pdf:
opus.install-plugin:
opus.install-html:
opus.info:
opus.dvi:
opus.pdf:
opus.html:
opus.man:
opus.mostlyclean:
opus.clean:
opus.distclean:
opus.maintainer-clean:
selftest-opus:
# make uninstall
opus.uninstall:
-rm -f gccopus$(exeext) opus1$(exeext)
-rm -f $(opus_OBJS)
# Used for handling bootstrap
opus.stage1: stage1-start
-mv opus/*$(objext) stage1/opus
opus.stage2: stage2-start
-mv opus/*$(objext) stage2/opus
opus.stage3: stage3-start
-mv opus/*$(objext) stage3/opus
opus.stage4: stage4-start
-mv opus/*$(objext) stage4/opus
opus.stageprofile: stageprofile-start
-mv opus/*$(objext) stageprofile/opus
opus.stagefeedback: stagefeedback-start
-mv opus/*$(objext) stagefeedback/opus
opusspec.cc
void
lang_specific_driver (struct cl_decoded_option ** /* in_decoded_options */,
unsigned int * /* in_decoded_options_count */,
int * /*in_added_libraries */)
{
}
/* Called before linking. Returns 0 on success and -1 on failure. */
int
lang_specific_pre_link (void)
{
/* Not used for Opus. */
return 0;
}
/* Number of extra output files that lang_specific_pre_link may generate. */
int lang_specific_extra_outfiles = 0; /* Not used for Opus. */
opus-lang.cc
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "target.h"
#include "tree.h"
#include "gimple-expr.h"
#include "diagnostic.h"
#include "opts.h"
#include "fold-const.h"
#include "gimplify.h"
#include "stor-layout.h"
#include "debug.h"
#include "convert.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "common/common-target.h"
#include <mpfr.h>
/* Language-dependent contents of a type. */
struct GTY (()) lang_type
{
char dummy;
};
/* Language-dependent contents of a decl. */
struct GTY (()) lang_decl
{
char dummy;
};
/* Language-dependent contents of an identifier. This must include a
tree_identifier. */
struct GTY (()) lang_identifier
{
struct tree_identifier common;
};
/* The resulting tree type. */
union GTY ((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), "
"TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN "
"(&%h.generic)) : NULL"))) lang_tree_node
{
union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic;
struct lang_identifier GTY ((tag ("1"))) identifier;
};
/* We don't use language_function. */
struct GTY (()) language_function
{
int dummy;
};
/* Language hooks. */
static bool
opus_langhook_init (void)
{
build_common_tree_nodes (false);
void_list_node = build_tree_list (NULL_TREE, void_type_node);
build_common_builtin_nodes ();
return true;
}
/* The main function of the frontend */
static void
opus_langhook_parse_file (void)
{
fprintf(stderr, "Hello world!\n");
}
static tree
opus_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
{
if (mode == TYPE_MODE (float_type_node))
return float_type_node;
if (mode == TYPE_MODE (double_type_node))
return double_type_node;
if (mode == TYPE_MODE (intQI_type_node))
return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
if (mode == TYPE_MODE (intHI_type_node))
return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
if (mode == TYPE_MODE (intSI_type_node))
return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
if (mode == TYPE_MODE (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
if (mode == TYPE_MODE (intTI_type_node))
return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
if (mode == TYPE_MODE (integer_type_node))
return unsignedp ? unsigned_type_node : integer_type_node;
if (mode == TYPE_MODE (long_integer_type_node))
return unsignedp ? long_unsigned_type_node : long_integer_type_node;
if (mode == TYPE_MODE (long_long_integer_type_node))
return unsignedp ? long_long_unsigned_type_node
: long_long_integer_type_node;
if (COMPLEX_MODE_P (mode))
{
if (mode == TYPE_MODE (complex_float_type_node))
return complex_float_type_node;
if (mode == TYPE_MODE (complex_double_type_node))
return complex_double_type_node;
if (mode == TYPE_MODE (complex_long_double_type_node))
return complex_long_double_type_node;
if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp)
return complex_integer_type_node;
}
/* gcc_unreachable */
return NULL;
}
static tree
opus_langhook_type_for_size (unsigned int bits ATTRIBUTE_UNUSED,
int unsignedp ATTRIBUTE_UNUSED)
{
gcc_unreachable ();
return NULL;
}
/* Record a builtin function. We just ignore builtin functions. */
static tree
opus_langhook_builtin_function (tree decl)
{
return decl;
}
static bool
opus_langhook_global_bindings_p (void)
{
gcc_unreachable ();
return true;
}
static tree
opus_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
{
gcc_unreachable ();
}
static tree
opus_langhook_getdecls (void)
{
return NULL;
}
tree
convert (tree type, tree expr)
{
if (type == error_mark_node
|| expr == error_mark_node
|| TREE_TYPE (expr) == error_mark_node)
return error_mark_node;
if (type == TREE_TYPE (expr))
return expr;
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
return fold_convert (type, expr);
switch (TREE_CODE (type))
{
case VOID_TYPE:
case BOOLEAN_TYPE:
return fold_convert (type, expr);
case INTEGER_TYPE:
return fold (convert_to_integer (type, expr));
case POINTER_TYPE:
return fold (convert_to_pointer (type, expr));
case REAL_TYPE:
return fold (convert_to_real (type, expr));
case COMPLEX_TYPE:
return fold (convert_to_complex (type, expr));
default:
break;
}
gcc_unreachable ();
}
#undef LANG_HOOKS_NAME
#undef LANG_HOOKS_INIT
#undef LANG_HOOKS_PARSE_FILE
#undef LANG_HOOKS_TYPE_FOR_MODE
#undef LANG_HOOKS_TYPE_FOR_SIZE
#undef LANG_HOOKS_BUILTIN_FUNCTION
#undef LANG_HOOKS_GLOBAL_BINDINGS_P
#undef LANG_HOOKS_PUSHDECL
#undef LANG_HOOKS_GETDECLS
#define LANG_HOOKS_NAME "GNU Opus"
#define LANG_HOOKS_INIT opus_langhook_init
#define LANG_HOOKS_PARSE_FILE opus_langhook_parse_file
#define LANG_HOOKS_TYPE_FOR_MODE opus_langhook_type_for_mode
#define LANG_HOOKS_TYPE_FOR_SIZE opus_langhook_type_for_size
#define LANG_HOOKS_BUILTIN_FUNCTION opus_langhook_builtin_function
#define LANG_HOOKS_GLOBAL_BINDINGS_P opus_langhook_global_bindings_p
#define LANG_HOOKS_PUSHDECL opus_langhook_pushdecl
#define LANG_HOOKS_GETDECLS opus_langhook_getdecls
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
#include "gt-opus-opus-lang.h"
#include "gtype-opus.h"
GCC with Opus support
user $
cd ../../../gcc-build
user $
../gcc-src/configure --prefix=$(pwd)/../gcc-install --disable-bootstrap --enable-languages=c,c++,opus
user $
make -j9
user $
make install -j9
Change to GCC build directory and compile GCC there. —-disable-bootstrap —-enable-languages
compiles GCC only once and allows GCC to compile C,C++,Opus programs. See these configuration options for more information.
Finally, make sure gcc executes opus1 when it sees .opus files:
user $
cd ../gcc-install/bin
user $
touch main.opus
user $
./gcc main.opus -c
Hello world!