From 82b94488aec7d79cee7e2e40d13732d766216d34 Mon Sep 17 00:00:00 2001 From: Fabrice Le Fessant Date: Fri, 13 Oct 2023 09:59:14 +0200 Subject: [PATCH] Add option --include FILE.h to add a #include in the generated C code This option has two side-effect: * the C file is compiled in the project directory (so that the included file can be found locally) * no prototype is generated, so the new header file must contain a prototype for all statically called functions --- NEWS | 10 +++++ cobc/ChangeLog | 9 +++++ cobc/cobc.c | 14 +++++++ cobc/cobc.h | 1 + cobc/codegen.c | 11 ++++++ cobc/help.c | 5 ++- doc/gnucobol.texi | 12 ++++++ tests/testsuite.src/used_binaries.at | 58 ++++++++++++++++++++++++++++ 8 files changed, 119 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index e7480c254..55977763f 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,16 @@ NEWS - user visible changes -*- outline -*- * Changes to the COBOL compiler (cobc) options: +** New option --copy COPYBOOK to load copybooks before parsing files. This + option can typically be used to perform replacements without modifying + the source code, or to add prototypes for external calls. + +** New option --include FILE.h to add a #include in the generated C file. + This option can typically be used to force the C compiler to check static + calls to externals. The files are put into quotes, unless they start by + '<'. Quoted files are expected to have absolute paths, as the C compiler + is called in a temp directory instead of the project directory. + ** output of unlimited errors may be requested by -fmax-errors=0, to stop compiliation at first error use -Wfatal-errors ** default value for -fmax-errors was changed from 128 to 20 diff --git a/cobc/ChangeLog b/cobc/ChangeLog index 982bea92e..4beeb50c3 100644 --- a/cobc/ChangeLog +++ b/cobc/ChangeLog @@ -1,4 +1,13 @@ +2023-10-12 Fabrice Le Fessant + + * cobc.c, codegen.c: new option --include FILE, to #include + additional files in the C generated code. Such files can be + used to statically check the number of arguments in static + calls, for example. The files are put into quotes, unless + they start by '<'. Since C files are compiled in a temp dir, + quoted files should be absolute paths. Implementing FR #176 + 2023-10-11 Fabrice Le Fessant * cobc.c, pplex.l: new option --copy COPYBOOK, to include a COPYBOOK diff --git a/cobc/cobc.c b/cobc/cobc.c index ac5f3e9ec..5285e3b7f 100644 --- a/cobc/cobc.c +++ b/cobc/cobc.c @@ -107,6 +107,7 @@ enum compile_level { #define CB_FLAG_GETOPT_DEFAULT_COLSEQ 15 #define CB_FLAG_GETOPT_MEMORY_CHECK 16 #define CB_FLAG_GETOPT_COPY_FILE 17 +#define CB_FLAG_GETOPT_INCLUDE_FILE 18 /* Info display limits */ @@ -234,6 +235,7 @@ const char *demangle_name = NULL; const char *cb_storage_file_name = NULL; const char *cb_call_extfh = NULL; struct cb_text_list *cb_copy_list = NULL; +struct cb_text_list *cb_include_file_list = NULL; struct cb_text_list *cb_include_list = NULL; struct cb_text_list *cb_depend_list = NULL; struct cb_text_list *cb_intrinsic_list = NULL; @@ -598,6 +600,7 @@ static const struct option long_options[] = { {"std", CB_RQ_ARG, NULL, '$'}, {"conf", CB_RQ_ARG, NULL, '&'}, {"copy", CB_RQ_ARG, NULL, CB_FLAG_GETOPT_COPY_FILE}, + {"include", CB_RQ_ARG, NULL, CB_FLAG_GETOPT_INCLUDE_FILE}, {"debug", CB_NO_ARG, NULL, 'd'}, {"ext", CB_RQ_ARG, NULL, 'e'}, /* note: kept *undocumented* until GC4, will be changed to '.' */ {"free", CB_NO_ARG, NULL, 'F'}, /* note: not assigned directly as this is only valid for */ @@ -3913,6 +3916,17 @@ process_command_line (const int argc, char **argv) cobc_strdup (cob_optarg)); break; + case CB_FLAG_GETOPT_INCLUDE_FILE: /* 18 */ + /* -include= : add #include "file.h" to + generated C file */ + if (strlen (cob_optarg) > (COB_MINI_MAX)) { + cobc_err_exit (COBC_INV_PAR, "--include"); + } + CB_TEXT_LIST_ADD (cb_include_file_list, + cobc_strdup (cob_optarg)); + cb_flag_c_decl_for_static_call = 0; + break; + case 'A': /* -A : Add options to C compile phase */ COBC_ADD_STR (cobc_cflags, " ", cob_optarg, NULL); diff --git a/cobc/cobc.h b/cobc/cobc.h index ee218308d..7b5f30bbd 100644 --- a/cobc/cobc.h +++ b/cobc/cobc.h @@ -474,6 +474,7 @@ extern FILE *cb_src_list_file; extern FILE *cb_depend_file; extern struct cb_text_list *cb_depend_list; extern struct cb_text_list *cb_copy_list; +extern struct cb_text_list *cb_include_file_list; extern struct cb_text_list *cb_include_list; extern struct cb_text_list *cb_intrinsic_list; extern struct cb_text_list *cb_extension_list; diff --git a/cobc/codegen.c b/cobc/codegen.c index 293e3b4e3..ab323a4f9 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -1829,6 +1829,17 @@ output_gnucobol_defines (const char *formatted_date) current_compile_tm.tm_sec; output_line ("#define COB_MODULE_TIME\t\t%d", i); + { + struct cb_text_list *l = cb_include_file_list ; + for (;l;l=l->next){ + if (l->text[0] == '<'){ + output_line ("#include %s", l->text); + } else { + output_line ("#include \"%s\"", l->text); + } + } + } + } /* CALL cache */ diff --git a/cobc/help.c b/cobc/help.c index 600db49da..3e95a2e19 100644 --- a/cobc/help.c +++ b/cobc/help.c @@ -116,8 +116,11 @@ cobc_print_usage_common_options (void) puts (_(" -X, --Xref specify cross reference in listing")); #endif puts (_(" -I add to copy/include search path")); - puts (_(" --copy include at beginning of file, as would COPY copybook.")); + puts (_(" --copy include at beginning of file,\n" + " as would COPY copybook.")); puts (_(" -L add to library search path")); + puts (_(" --include add a #include \"file.h\" at the beginning of the C\n" + " generated file (implies -fno-gen-c-decl-static-call)")); puts (_(" -l link the library ")); puts (_(" -K generate CALL to as static")); puts (_(" -D define for COBOL compilation")); diff --git a/doc/gnucobol.texi b/doc/gnucobol.texi index 24791737e..7aa0abd4c 100644 --- a/doc/gnucobol.texi +++ b/doc/gnucobol.texi @@ -373,6 +373,18 @@ another process. You can manually set an output file using @option{-o}. Include @file{copybook} at the beginning of the source code, as if @code{COPY copybook} had been parsed. +@item --include @var{file.h} +Add a @code{#include} @file{file.h} at the beginning of the generated +C source file. The file name is put into quotes, unless it starts by +@code{<}. Quoted files should be absolute paths, since C files are compiled +in temporary directories. +The option also implies @option{-fno-gen-c-decl-static-call}. +This option can be used to check function prototypes when +static calls are used. When this option is used, the source file is +compiled in the project directory (instead of the temp directory), and +no prototypes are generated, so ALL static call functions must appear +in the header file, with GnuCOBOL compatible types. + @item -C Translation only. COBOL source files are translated into C files. The output is saved in file @file{*.c}. diff --git a/tests/testsuite.src/used_binaries.at b/tests/testsuite.src/used_binaries.at index b99b7e6f4..817d61c50 100644 --- a/tests/testsuite.src/used_binaries.at +++ b/tests/testsuite.src/used_binaries.at @@ -1081,3 +1081,61 @@ HOME/prog.cob:14: warning: ignoring redundant . AT_CLEANUP + +AT_SETUP([check include header file]) +AT_KEYWORDS([-include]) + +AT_DATA([file.h], [ +extern void f(char *, long ); +]) +AT_DATA([prog.cob], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + CALL "f" USING "Hello". +]) + +# No check, program seems correct + +AT_CHECK([$COBC -m -fstatic-call prog.cob], [0], [], []) + +# We ignore the error output, as it depends on the C compiler in use + +AT_CHECK([$COBC -m --include "$PWD/file.h" -fstatic-call prog.cob], [1], [], [ignore]) +AT_DATA([prog2.cob], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 long USAGE BINARY-C-LONG. + PROCEDURE DIVISION. + CALL "f" USING "Hello" BY VALUE long RETURNING NOTHING. +]) + +AT_CHECK([$COBC -m --include "$PWD/file.h" -fstatic-call prog2.cob], [0], [], []) + +AT_CHECK([$COBC -I . -m --include "file.h" -fstatic-call prog2.cob], [0], [], []) + +# We can use --copy to check a CALL against a prototype. However, this +# feature is not fully supported by GnuCOBOL yet, so we get some +# warnings. For exemple: +# * not putting RETURNING triggers an error +# * putting RETURNING NOTHING is not supported +# * putting RETURNING OMITTED is ok, but triggers a warning (see stderr) + +AT_DATA([f.copy], [ + IDENTIFICATION DIVISION. + PROGRAM-ID. f PROTOTYPE. + DATA DIVISION. + LINKAGE SECTION. + 01 a PIC X(20). + 01 b BINARY-C-LONG. + PROCEDURE DIVISION USING a BY VALUE b RETURNING OMITTED. + END PROGRAM f. +]) + +AT_CHECK([$COMPILE_MODULE -Wno-unfinished --copy "f.copy" -fstatic-call prog2.cob], [0], [], +[prog2.cob:8: warning: unexpected RETURNING item +]) + +AT_CLEANUP