Re: pg_bsd_indent compiles bytecode

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: pg_bsd_indent compiles bytecode
Дата
Msg-id 445644.1593480468@sss.pgh.pa.us
обсуждение исходный текст
Ответ на pg_bsd_indent compiles bytecode  (Alvaro Herrera <alvherre@2ndquadrant.com>)
Ответы Re: pg_bsd_indent compiles bytecode  (Andres Freund <andres@anarazel.de>)
Список pgsql-hackers
I wrote:
> Andres Freund <andres@anarazel.de> writes:
>> The way that pg_bsd_indent defines its variables isn't standard C, as
>> far as I can tell, which explains the errors I was getting. All the
>> individual files include indent_globs.h, which declares/defines a bunch
>> of variables. Since it doesn't use extern, they'll all end up as full
>> definitions in each .o when -fno-common is used (the default now), hence
>> the multiple definition errors. The only reason it works with -fcommon
>> is that they'll end up processed as weak symbols and 'deduplicated' at
>> link time.

> Ugh.  I agree that's pretty bogus, even if there's anything in the
> C standard that allows it.  I'll put it on my to-do list.

I pushed the attached patch to the pg_bsd_indent repo.  Perhaps Piotr
would like to absorb it into upstream.

I don't intend to mark pg_bsd_indent with a new release number for
this --- for people who successfully compiled, it's the same as before.

            regards, tom lane

commit acb2f0a7f3689805b954ea19a927b5021fc69409
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date:   Mon Jun 29 21:19:16 2020 -0400

    Avoid duplicate declarations of bsdindent's global variables.

    Arrange for all the variable declarations in indent_globs.h to look
    like "extern" declarations to every .c file except indent.c.
    This prevents linker failure due to duplicated global variables when
    the code is built with -fno-common, which is soon to be gcc's default.

    The method of temporarily #define'ing "extern" to empty is a hack,
    no doubt, but it avoids requiring a duplicate set of variable
    definitions, so it seemed like the best way.

    Discussion: https://postgr.es/m/20200629165051.xlfqhstajf6ynxyv@alap3.anarazel.de

diff --git a/indent.c b/indent.c
index 62d4d01..d3a0ece 100644
--- a/indent.c
+++ b/indent.c
@@ -49,6 +49,10 @@ static char sccsid[] = "@(#)indent.c    5.17 (Berkeley) 6/7/93";
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+
+/* Tell indent_globs.h to define our global variables here */
+#define DECLARE_INDENT_GLOBALS 1
+
 #include "indent_globs.h"
 #include "indent_codes.h"
 #include "indent.h"
diff --git a/indent_globs.h b/indent_globs.h
index d018af1..398784b 100644
--- a/indent_globs.h
+++ b/indent_globs.h
@@ -50,9 +50,16 @@
 #define true  1
 #endif

+/*
+ * Exactly one calling file should define this symbol.  The global variables
+ * will be defined in that file, and just referenced elsewhere.
+ */
+#ifdef DECLARE_INDENT_GLOBALS
+#define extern
+#endif

-FILE       *input;        /* the fid for the input file */
-FILE       *output;        /* the output file */
+extern FILE *input;        /* the fid for the input file */
+extern FILE *output;        /* the output file */

 #define CHECK_SIZE_CODE(desired_size) \
     if (e_code + (desired_size) >= l_code) { \
@@ -106,94 +113,94 @@ FILE       *output;        /* the output file */
         s_token = tokenbuf + 1; \
     }

-char       *labbuf;        /* buffer for label */
-char       *s_lab;        /* start ... */
-char       *e_lab;        /* .. and end of stored label */
-char       *l_lab;        /* limit of label buffer */
+extern char *labbuf;        /* buffer for label */
+extern char *s_lab;        /* start ... */
+extern char *e_lab;        /* .. and end of stored label */
+extern char *l_lab;        /* limit of label buffer */

-char       *codebuf;        /* buffer for code section */
-char       *s_code;        /* start ... */
-char       *e_code;        /* .. and end of stored code */
-char       *l_code;        /* limit of code section */
+extern char *codebuf;        /* buffer for code section */
+extern char *s_code;        /* start ... */
+extern char *e_code;        /* .. and end of stored code */
+extern char *l_code;        /* limit of code section */

-char       *combuf;        /* buffer for comments */
-char       *s_com;        /* start ... */
-char       *e_com;        /* ... and end of stored comments */
-char       *l_com;        /* limit of comment buffer */
+extern char *combuf;        /* buffer for comments */
+extern char *s_com;        /* start ... */
+extern char *e_com;        /* ... and end of stored comments */
+extern char *l_com;        /* limit of comment buffer */

 #define token s_token
-char       *tokenbuf;        /* the last token scanned */
-char       *s_token;
-char       *e_token;
-char       *l_token;
+extern char *tokenbuf;        /* the last token scanned */
+extern char *s_token;
+extern char *e_token;
+extern char *l_token;

-char       *in_buffer;        /* input buffer */
-char       *in_buffer_limit;    /* the end of the input buffer */
-char       *buf_ptr;        /* ptr to next character to be taken from
+extern char *in_buffer;        /* input buffer */
+extern char *in_buffer_limit;    /* the end of the input buffer */
+extern char *buf_ptr;        /* ptr to next character to be taken from
                  * in_buffer */
-char       *buf_end;        /* ptr to first after last char in in_buffer */
+extern char *buf_end;        /* ptr to first after last char in in_buffer */

-char        sc_buf[sc_size];    /* input text is saved here when looking for
+extern char  sc_buf[sc_size];    /* input text is saved here when looking for
                  * the brace after an if, while, etc */
-char       *save_com;        /* start of the comment stored in sc_buf */
-char       *sc_end;        /* pointer into save_com buffer */
+extern char *save_com;        /* start of the comment stored in sc_buf */
+extern char *sc_end;        /* pointer into save_com buffer */

-char       *bp_save;        /* saved value of buf_ptr when taking input
+extern char *bp_save;        /* saved value of buf_ptr when taking input
                  * from save_com */
-char       *be_save;        /* similarly saved value of buf_end */
+extern char *be_save;        /* similarly saved value of buf_end */


-int         found_err;
-int         blanklines_after_declarations;
-int         blanklines_before_blockcomments;
-int         blanklines_after_procs;
-int         blanklines_around_conditional_compilation;
-int         swallow_optional_blanklines;
-int         n_real_blanklines;
-int         prefix_blankline_requested;
-int         postfix_blankline_requested;
-int         break_comma;    /* when true and not in parens, break after a
+extern int   found_err;
+extern int   blanklines_after_declarations;
+extern int   blanklines_before_blockcomments;
+extern int   blanklines_after_procs;
+extern int   blanklines_around_conditional_compilation;
+extern int   swallow_optional_blanklines;
+extern int   n_real_blanklines;
+extern int   prefix_blankline_requested;
+extern int   postfix_blankline_requested;
+extern int   break_comma;    /* when true and not in parens, break after a
                  * comma */
-int         btype_2;        /* when true, brace should be on same line as
+extern int   btype_2;        /* when true, brace should be on same line as
                  * if, while, etc */
-float       case_ind;        /* indentation level to be used for a "case
+extern float case_ind;        /* indentation level to be used for a "case
                  * n:" */
-int         code_lines;        /* count of lines with code */
-int         had_eof;        /* set to true when input is exhausted */
-int         line_no;        /* the current line number. */
-int         max_col;        /* the maximum allowable line length */
-int         verbose;        /* when true, non-essential error messages are
+extern int   code_lines;    /* count of lines with code */
+extern int   had_eof;        /* set to true when input is exhausted */
+extern int   line_no;        /* the current line number. */
+extern int   max_col;        /* the maximum allowable line length */
+extern int   verbose;        /* when true, non-essential error messages are
                  * printed */
-int         cuddle_else;    /* true if else should cuddle up to '}' */
-int         star_comment_cont;    /* true iff comment continuation lines should
+extern int   cuddle_else;    /* true if else should cuddle up to '}' */
+extern int   star_comment_cont;    /* true iff comment continuation lines should
                  * have stars at the beginning of each line. */
-int         comment_delimiter_on_blankline;
-int         troff;        /* true iff were generating troff input */
-int         procnames_start_line;    /* if true, the names of procedures
+extern int   comment_delimiter_on_blankline;
+extern int   troff;        /* true iff were generating troff input */
+extern int   procnames_start_line;    /* if true, the names of procedures
                      * being defined get placed in column
                      * 1 (ie. a newline is placed between
                      * the type of the procedure and its
                      * name) */
-int         proc_calls_space;    /* If true, procedure calls look like:
+extern int   proc_calls_space;    /* If true, procedure calls look like:
                  * foo(bar) rather than foo (bar) */
-int         format_block_comments;    /* true if comments beginning with
+extern int   format_block_comments;    /* true if comments beginning with
                      * `/ * \n' are to be reformatted */
-int         format_col1_comments;    /* If comments which start in column 1
+extern int   format_col1_comments;    /* If comments which start in column 1
                      * are to be magically reformatted
                      * (just like comments that begin in
                      * later columns) */
-int         inhibit_formatting;    /* true if INDENT OFF is in effect */
-int         suppress_blanklines;/* set iff following blanklines should be
+extern int   inhibit_formatting;    /* true if INDENT OFF is in effect */
+extern int   suppress_blanklines;/* set iff following blanklines should be
                  * suppressed */
-int         continuation_indent;/* set to the indentation between the edge of
+extern int   continuation_indent;/* set to the indentation between the edge of
                  * code and continuation lines */
-int         lineup_to_parens;    /* if true, continued code within parens will
+extern int   lineup_to_parens;    /* if true, continued code within parens will
                  * be lined up to the open paren */
-int         lineup_to_parens_always;    /* if true, do not attempt to keep
+extern int   lineup_to_parens_always;    /* if true, do not attempt to keep
                      * lined-up code within the margin */
-int         Bill_Shannon;    /* true iff a blank should always be inserted
+extern int   Bill_Shannon;    /* true iff a blank should always be inserted
                  * after sizeof */
-int         blanklines_after_declarations_at_proctop;    /* This is vaguely
+extern int   blanklines_after_declarations_at_proctop;    /* This is vaguely
                              * similar to
                              * blanklines_after_decla
                              * rations except that
@@ -206,26 +213,28 @@ int         blanklines_after_declarations_at_proctop;    /* This is vaguely
                              * to be generated even
                              * if there are no
                              * declarations */
-int         block_comment_max_col;
-int         extra_expression_indent;    /* true if continuation lines from the
+extern int   block_comment_max_col;
+extern int   extra_expression_indent;    /* true if continuation lines from the
                      * expression part of "if(e)",
                      * "while(e)", "for(e;e;e)" should be
                      * indented an extra tab stop so that
                      * they don't conflict with the code
                      * that follows */
-int        function_brace_split;    /* split function declaration and
+extern int   function_brace_split;    /* split function declaration and
                      * brace onto separate lines */
-int        use_tabs;            /* set true to use tabs for spacing,
+extern int   use_tabs;            /* set true to use tabs for spacing,
                      * false uses all spaces */
-int        auto_typedefs;        /* set true to recognize identifiers
+extern int   auto_typedefs;        /* set true to recognize identifiers
                      * ending in "_t" like typedefs */
-int        space_after_cast;        /* "b = (int) a" vs "b = (int)a" */
-int        postgres_tab_rules;        /* use Postgres tab-vs-space rules */
-int        tabsize;            /* the size of a tab */
-int        else_endif_com_ind;        /* the column in which comments to
+extern int   space_after_cast;        /* "b = (int) a" vs "b = (int)a" */
+extern int   postgres_tab_rules;    /* use Postgres tab-vs-space rules */
+extern int   tabsize;            /* the size of a tab */
+extern int   else_endif_com_ind;    /* the column in which comments to
                      * the right of #else and #endif
                      * should start */

+extern int   ifdef_level;
+
 struct parser_state {
     int         last_token;
     int         p_stack[256];    /* this is the parsers stack */
@@ -322,8 +331,13 @@ struct parser_state {
     int         tos;        /* pointer to top of stack */
     char        procname[100];    /* The name of the current procedure */
     int         just_saw_decl;
-}           ps;
+};

-int         ifdef_level;
-struct parser_state state_stack[5];
-struct parser_state match_state[5];
+extern struct parser_state ps;
+extern struct parser_state state_stack[5];
+extern struct parser_state match_state[5];
+
+/* Undo previous hackery */
+#ifdef DECLARE_INDENT_GLOBALS
+#undef extern
+#endif

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Andres Freund
Дата:
Сообщение: Re: More efficient RI checks - take 2
Следующее
От: Tom Lane
Дата:
Сообщение: Re: pg_bsd_indent compiles bytecode