[Bug c++/43601] Enormous increase in DLL object files size in 4.5

silver24k at gmail dot com gcc-bugzilla@gcc.gnu.org
Fri Sep 24 20:33:00 GMT 2010


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43601

Yu Simin <silver24k at gmail dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |silver24k at gmail dot com

--- Comment #26 from Yu Simin <silver24k at gmail dot com> 2010-09-24 20:21:08 UTC ---
[English is not my native language ...]
In GCC 4.5 or later, both the compilation time and the sizes of the generated
object files is far longer or far larger than MSVC when PCH is enabled in both
of the compilers.
MSVC requires a DUMMY source file eg:dummy.cpp to be used when generating the
PCH file and will generate an object file eg:dummy.obj. But the dummy object
file is not dummy at all. It contains all the common codes generated from the
sources/headers of the PCH. 
In GCC, PCH is just preprocess + compiling, no common code (is this case
dllexports) generating. so every compilation unit will have to generate the
codes in the PCH file again and again while MSVC will not generate them once
more.

We may add a flag for example -fgenerate-pch-codes/-fno-generate-pch-codes (or
some pragmas) to make GCC work similar to MSVC.
For example, if we make -fno-generate-pch-codes the default
gcc -O2 -o foo.h.gch foo.h
gcc -O2 -fgenerate-pch-codes -o dummy.o dymmy.cpp  # add this to generate the
codes of foo.h to dummy.o
# assuming that other1.cpp/other2.cpp use foo.h.gch
gcc -O2 -o other1.o other1.cpp # no code in foo.h will be generated on other1.o
gcc -O2 -o other2.o other2.cpp # no code in foo.h will be generated on other2.o
...


Here is my patch (picked from my local copy so maybe someting is missing, a bit
different from above and only handle the dllexport case and may have bug for
trunk). with this patch I successfully built wxWidget 2.8.10 & trunk (slightly
modified to make PCH enabled for GCC and added a dummy file with my pragma
below), the monolithic DLL seems ok (~9M in size, at least the wxWidget demos &
examples work well). 


I only care about the compilation time and the size of objects because it make
ld failed to link the wxWidget DLL on my windows box (I do not want to revert
the dllexports change. before this patch is out, I had to link it on 64bit
linux in VirtualBox by a cross toolchain and the generated DLL is ~25MB! This
size explosion seems to be caused by the inline strategy, but I did not look
into it)

I won't have any time to maintain the patch, just hope it will be useful to
help solving the problem finally.

In this patch I've introduced one flag
-fpch-ignore-inline-dllexports (-fno-pch-ignore-inline-dllexports)
and one pragma
#pragma pch_ignore_inline_dllexports on/off


Index: c-family/c-pragma.c
===================================================================
--- c-family/c-pragma.c (版本 164605)
+++ c-family/c-pragma.c (工作副本)
@@ -1314,7 +1314,9 @@
   if (!flag_preprocess_only)
     cpp_register_deferred_pragma (parse_in, "GCC", "pch_preprocess",
                                  PRAGMA_GCC_PCH_PREPROCESS, false, false);
-
+  cpp_register_deferred_pragma (parse_in, "GCC",
"pch_ignore_inline_dllexports",
+                               PRAGMA_GCC_PCH_IGNORE_INLINE_DLLEXPORTS, false,
false);
+
 #ifdef HANDLE_PRAGMA_PACK
 #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION
   c_register_pragma_with_expansion (0, "pack", handle_pragma_pack);
Index: c-family/c-pragma.h
===================================================================
--- c-family/c-pragma.h (版本 164605)
+++ c-family/c-pragma.h (工作副本)
@@ -47,6 +47,8 @@

   PRAGMA_GCC_PCH_PREPROCESS,

+  PRAGMA_GCC_PCH_IGNORE_INLINE_DLLEXPORTS,
+
   PRAGMA_FIRST_EXTERNAL
 } pragma_kind;

Index: cgraph.h
===================================================================
--- cgraph.h    (版本 164605)
+++ cgraph.h    (工作副本)
@@ -125,6 +125,10 @@
   /* True if the function is going to be emitted in some other translation
      unit, referenced from vtable.  */
   unsigned vtable_method : 1;
 };

 /* Information about the function that needs to be computed globally
Index: tree.h
===================================================================
--- tree.h      (版本 164605)
+++ tree.h      (工作副本)
@@ -2706,6 +2706,13 @@
 #define DECL_GIMPLE_REG_P(DECL) \
   DECL_COMMON_CHECK (DECL)->decl_common.gimple_reg_flag

+/* To support fkeep-dllexport-inline-functions-in-pch,
+   indicates that the dllexport inline function is defined in PCH */
+#define DECL_DLLEXPORT_INLINE_IN_PCH_P(DECL) \
+  DECL_COMMON_CHECK (DECL)->decl_common.dllexport_inline_in_pch
+
+
 struct GTY(()) tree_decl_common {
   struct tree_decl_minimal common;
   tree size;
@@ -2759,6 +2765,10 @@
   unsigned int off_align : 8;

   /* 24-bits unused.  */
+
+  /* To support fkeep-dllexport-inline-functions-in-pch */
+  unsigned int dllexport_inline_in_pch : 1;

   /* DECL_ALIGN.  It should have the same size as TYPE_ALIGN.  */
   unsigned int align;
Index: common.opt
===================================================================
--- common.opt  (版本 164605)
+++ common.opt  (工作副本)
@@ -1023,6 +1023,10 @@
 Common Report Var(flag_keep_inline_functions)
 Generate code for functions even if they are fully inlined

+fpch-ignore-inline-dllexports
+Common Report Var(flag_pch_ignore_inline_dllexports) Init(0)
+Do not generate code for inline functions defined in the PCH file
+
 fkeep-static-consts
 Common Report Var(flag_keep_static_consts) Init(1)
 Emit static const variables even if they are not used
Index: cp/semantics.c
===================================================================
--- cp/semantics.c      (版本 164605)
+++ cp/semantics.c      (工作副本)
@@ -3436,9 +3436,19 @@
         be emitted; there may be callers in other DLLs.  */
       if ((flag_keep_inline_functions
           && DECL_DECLARED_INLINE_P (fn)
-          && !DECL_REALLY_EXTERN (fn))
-         || lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))
+          && !DECL_REALLY_EXTERN (fn)))
        mark_needed (fn);
+      else if(lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))
+        {
+         if (pch_file)
+           {
+             DECL_DLLEXPORT_INLINE_IN_PCH_P (fn) = 1;
+           }
+         mark_needed (fn);
+        }
+
     }

   /* There's no reason to do any of the work here if we're only doing
Index: cp/decl2.c
===================================================================
--- cp/decl2.c  (版本 164605)
+++ cp/decl2.c  (工作副本)
@@ -1784,6 +1784,13 @@
      COMDAT until that point.  */
   gcc_assert (at_eof);

+  if (DECL_DLLEXPORT_INLINE_IN_PCH_P (decl)
+      && flag_pch_ignore_inline_dllexports
+      && !pch_file)
+    return false;
+
   /* All entities with external linkage that are not COMDAT should be
      emitted; they may be referred to from other object files.  */
   if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
Index: cp/parser.c
===================================================================
--- cp/parser.c (版本 164605)
+++ cp/parser.c (工作副本)
@@ -23828,6 +23828,30 @@
   cp_lexer_get_preprocessor_token (NULL, first_token);
 }

+static void
+cp_parser_pch_ignore_inline_dllexports (cp_parser *parser)
+{
+  cp_token* tok;
+  /* Handle pch_ignore_inline_exports */
+  tok = cp_lexer_peek_token (parser->lexer);
+  if (tok->type == CPP_NAME)
+    {
+      const char *p = IDENTIFIER_POINTER (tok->u.value);
+
+      if (!strcmp ("on", p))
+       flag_pch_ignore_inline_dllexports = 1;
+      else if(!strcmp ("off", p))
+       flag_pch_ignore_inline_dllexports = 0;
+      else
+       error_at (tok->location,
+                 "expected %<on%> or %<off%>");
+      cp_lexer_consume_token (parser->lexer);
+    }
+  else
+    flag_pch_ignore_inline_dllexports = 1;
+
+}
+
 /* Normal parsing of a pragma token.  Here we can (and must) use the
    regular lexer.  */

@@ -23849,6 +23873,10 @@
                "%<#pragma GCC pch_preprocess%> must be first");
       break;

+    case PRAGMA_GCC_PCH_IGNORE_INLINE_DLLEXPORTS:
+      cp_parser_pch_ignore_inline_dllexports (parser);
+      break;
+
     case PRAGMA_OMP_BARRIER:
       switch (context)
        {
Index: c-parser.c
===================================================================
--- c-parser.c  (版本 164605)
+++ c-parser.c  (工作副本)
@@ -7130,6 +7130,29 @@
 }

+static void
+c_parser_pragma_pch_ignore_inline_dllexports (c_parser *parser)
+{
+  c_parser_consume_pragma (parser);
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token
(parser)->value);
+      if (!strcmp ("on", p))
+       flag_pch_ignore_inline_dllexports = 1;
+      else if(!strcmp ("off", p))
+       flag_pch_ignore_inline_dllexports = 0;
+      else
+       c_parser_error (parser, "expected %<on%> or %<off%>");
+      c_parser_consume_token (parser);
+    }
+  else
+    flag_pch_ignore_inline_dllexports = 1;
+
+  parser->error = true;
+  c_parser_skip_to_pragma_eol (parser);
+}
+
 /* Handle pragmas.  Some OpenMP pragmas are associated with, and therefore
    should be considered, statements.  ALLOW_STMT is true if we're within
    the context of a function and such pragmas are to be allowed.  Returns
@@ -7194,6 +7217,10 @@
       c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
       return false;

+    case PRAGMA_GCC_PCH_IGNORE_INLINE_DLLEXPORTS:
+      c_parser_pragma_pch_ignore_inline_dllexports (parser);
+      return false;
+
     default:
       if (id < PRAGMA_FIRST_EXTERNAL)
        {

-- 
Configure bugmail: http://gcc.gnu.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.



More information about the Gcc-bugs mailing list