I wrote: > Andres Freund <and...@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 <t...@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.xlfqhstajf6yn...@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