Support -std= command line option

SWIG now supports command line options -std=cXX and -std=c++XX to
specify the C/C++ standards version.  The only effect of these options
is to set appropriate values for __STDC_VERSION__ and __cplusplus
respectively, which is useful if you're wrapping headers which have
preprocessor checks based on their values.

Closes #2591
This commit is contained in:
Olly Betts 2023-11-09 11:53:37 +13:00
parent 432daea78c
commit 13eca97013
6 changed files with 149 additions and 29 deletions

View File

@ -7,6 +7,26 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.0 (in progress) Version 4.2.0 (in progress)
=========================== ===========================
2023-11-09: olly
#2591 SWIG now supports command line options -std=cXX and
-std=c++XX to specify the C/C++ standards version. The only effect
of these options is to set appropriate values for __STDC_VERSION__
and __cplusplus respectively, which is useful if you're wrapping
headers which have preprocessor checks based on their values.
2023-11-09: olly
SWIG now defines __STDC__ to 1 to match the behaviour of ISO C/C++
compilers - previously it had an empty value.
*** POTENTIAL INCOMPATIBILITY ***
2023-11-09: olly
When -c++ is used, SWIG now defines __cplusplus to be 199711L (the
value for C++98) by default - previously its value was set to
__cplusplus.
*** POTENTIAL INCOMPATIBILITY ***
2023-11-08: emmenlau 2023-11-08: emmenlau
#2480 [C#] Add std_unordered_map.i for wrapping std::std_unordered_map, implementing #2480 [C#] Add std_unordered_map.i for wrapping std::std_unordered_map, implementing
C# System.Collections.Generic.IDictionary<>. C# System.Collections.Generic.IDictionary<>.
@ -555,22 +575,6 @@ Version 4.2.0 (in progress)
purpose in over 20 years, and has never been documented outside of purpose in over 20 years, and has never been documented outside of
CHANGES. CHANGES.
2023-05-18: olly
SWIG now defines __STDC__ to 1 to match the behaviour of ISO C/C++
compilers, rather than to have an empty value.
*** POTENTIAL INCOMPATIBILITY ***
2023-05-18: olly
#2591 The value of __cplusplus SWIG defines can now be overridden
on the command line, e.g. using -D__cplusplus=201103L which is
useful if you're wrapping headers which have preprocessor checks
based on its value. By default SWIG now defines __cplusplus to
199711L (the value for C++98) rather than setting its value to
be __cplusplus.
*** POTENTIAL INCOMPATIBILITY ***
2023-05-18: olly 2023-05-18: olly
#2591 Add new -U command line option to undefine a preprocessor #2591 Add new -U command line option to undefine a preprocessor
symbol. symbol.

View File

@ -164,8 +164,9 @@ In addition, SWIG defines the following set of standard C/C++ macros:
<pre> <pre>
__LINE__ Current line number __LINE__ Current line number
__FILE__ Current file name __FILE__ Current file name
__STDC__ Defined to indicate ISO C __STDC__ Defined to indicate ISO C/C++
__cplusplus Defined when -c++ option used __cplusplus Defined when -c++ option used, value controlled by <tt>-std=c++NN</tt>
__STDC_VERSION__ May be defined when -c++ option is not used, value controlled by <tt>-std=cNN</tt>
</pre> </pre>
</div> </div>
@ -177,13 +178,16 @@ have an empty value.
<p> <p>
Since SWIG 4.2.0, <tt>__cplusplus</tt> is defined to <tt>199711L</tt> Since SWIG 4.2.0, <tt>__cplusplus</tt> is defined to <tt>199711L</tt>
(the value for C++98) but you can override this by defining it (the value for C++98) by default. Before this SWIG always defined it to have
explicitly on the SWIG command line if you are wrapping headers the <b>value</b> <tt>__cplusplus</tt>.
which have preprocessor checks based on its value (e.g. use </p>
<tt>-D__cplusplus=201103L</tt> to set it to the value for C++11).
Before this SWIG always defined it to have the <b>value</b> <p>
<tt>__cplusplus</tt> and attempting to use <tt>-D__cplusplus</tt> Since SWIG 4.2.0, SWIG supports command line options <tt>-std=cXX</tt> and
to change this gave an error. <tt>-std=c++XX</tt> to specify the C/C++ standards version. The only effect of
these options is to set appropriate values for <tt>__STDC_VERSION__</tt> and
<tt>__cplusplus</tt> respectively, which is useful if you're wrapping
headers which have preprocessor checks based on their values.
</p> </p>
<p> <p>

View File

@ -375,6 +375,7 @@ CPP_TEST_CASES += \
pointer_reference \ pointer_reference \
preproc_constants \ preproc_constants \
preproc_cpp \ preproc_cpp \
preproc_predefined_stdcpp \
primitive_ref \ primitive_ref \
private_assign \ private_assign \
proxycode \ proxycode \
@ -824,6 +825,7 @@ C_TEST_CASES += \
preproc_include \ preproc_include \
preproc_line_file \ preproc_line_file \
preproc_predefined \ preproc_predefined \
preproc_predefined_stdc \
register_par \ register_par \
ret_by_value \ ret_by_value \
simple_array \ simple_array \
@ -853,6 +855,8 @@ MULTI_CPP_TEST_CASES += \
wallkw.cpptest: SWIGOPT += -Wallkw wallkw.cpptest: SWIGOPT += -Wallkw
preproc_include.ctest: SWIGOPT += -includeall preproc_include.ctest: SWIGOPT += -includeall
command_line_define.ctest: SWIGOPT += -DFOO -DBAR=123 -DBAZ -UBAZ -UNOTSET command_line_define.ctest: SWIGOPT += -DFOO -DBAR=123 -DBAZ -UBAZ -UNOTSET
preproc_predefined_stdc.ctest: SWIGOPT += -std=c23
preproc_predefined_stdcpp.cpptest: SWIGOPT += -std=c++23
# Allow modules to define temporarily failing tests. # Allow modules to define temporarily failing tests.
C_TEST_CASES := $(filter-out $(FAILING_C_TESTS),$(C_TEST_CASES)) C_TEST_CASES := $(filter-out $(FAILING_C_TESTS),$(C_TEST_CASES))

View File

@ -0,0 +1,24 @@
%module preproc_predefined_stdc
// Test handling of -std=c23
// __STDC__ should still have value 1.
#ifndef __STDC__
# error __STDC__ not defined at SWIG-time
#endif
#if __STDC__-0 != 1
# error __STDC__ value not 1 at SWIG-time
#endif
// __cplusplus should not be defined.
#ifdef __cplusplus
# error __cplusplus defined at SWIG-time but should not be
#endif
// __STDC_VERSION__ should be suitably defined.
#ifndef __STDC_VERSION__
# error __STDC_VERSION__ not defined at SWIG-time
#endif
#if __STDC_VERSION__ != 202311L
# error __STDC_VERSION__ value not 202311L at SWIG-time
#endif

View File

@ -0,0 +1,24 @@
%module preproc_predefined_stdcpp
// Test handling of -std=c++23
// __STDC__ should still have value 1.
#ifndef __STDC__
# error __STDC__ not defined at SWIG-time
#endif
#if __STDC__-0 != 1
# error __STDC__ value not 1 at SWIG-time
#endif
// __STDC_VERSION__ should not be defined.
#ifdef __STDC_VERSION__
# error __STDC_VERSION__ defined at SWIG-time but should not be
#endif
// __cplusplus should be suitably defined.
#ifndef __cplusplus
# error __cplusplus not defined at SWIG-time
#endif
#if __cplusplus != 202302L
# error __cplusplus value not 202302L at SWIG-time
#endif

View File

@ -210,6 +210,8 @@ static String *external_runtime_name = 0;
enum { STAGE1=1, STAGE2=2, STAGE3=4, STAGE4=8, STAGEOVERFLOW=16 }; enum { STAGE1=1, STAGE2=2, STAGE3=4, STAGE4=8, STAGEOVERFLOW=16 };
static List *libfiles = 0; static List *libfiles = 0;
static List *all_output_files = 0; static List *all_output_files = 0;
static const char *stdcpp_define = NULL;
static const char *stdc_define = NULL;
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* check_extension() * check_extension()
@ -463,6 +465,46 @@ static void getoptions(int argc, char *argv[]) {
// Undocumented // Undocumented
Swig_cparse_cplusplusout(1); Swig_cparse_cplusplusout(1);
Swig_mark_arg(i); Swig_mark_arg(i);
} else if (strncmp(argv[i], "-std=c", 6) == 0) {
const char *std = argv[i] + 6;
if (strncmp(std, "++", 2) == 0) {
std += 2;
if (strcmp(std, "98") == 0 || strcmp(std, "03") == 0) {
stdcpp_define = "__cplusplus 199711L";
} else if (strcmp(std, "11") == 0) {
stdcpp_define = "__cplusplus 201103L";
} else if (strcmp(std, "14") == 0) {
stdcpp_define = "__cplusplus 201402L";
} else if (strcmp(std, "17") == 0) {
stdcpp_define = "__cplusplus 201703L";
} else if (strcmp(std, "20") == 0) {
stdcpp_define = "__cplusplus 202002L";
} else if (strcmp(std, "23") == 0) {
stdcpp_define = "__cplusplus 202302L";
} else {
Printf(stderr, "Unrecognised C++ standard version in option '%s'\n", argv[i]);
Exit(EXIT_FAILURE);
}
} else {
if (strcmp(std, "89") == 0 || strcmp(std, "90") == 0) {
stdc_define = NULL;
} else if (strcmp(std, "95") == 0) {
stdc_define = "__STDC_VERSION__ 199409L";
} else if (strcmp(std, "99") == 0) {
stdc_define = "__STDC_VERSION__ 199901L";
} else if (strcmp(std, "11") == 0) {
stdc_define = "__STDC_VERSION__ 201112L";
} else if (strcmp(std, "17") == 0 || strcmp(std, "18") == 0) {
// Both GCC and clang accept -std=c18 as well as -std=c17.
stdc_define = "__STDC_VERSION__ 201710L";
} else if (strcmp(std, "23") == 0) {
stdc_define = "__STDC_VERSION__ 202311L";
} else {
Printf(stderr, "Unrecognised C standard version in option '%s'\n", argv[i]);
Exit(EXIT_FAILURE);
}
}
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-fcompact") == 0) { } else if (strcmp(argv[i], "-fcompact") == 0) {
Wrapper_compact_print_mode_set(1); Wrapper_compact_print_mode_set(1);
Swig_mark_arg(i); Swig_mark_arg(i);
@ -890,10 +932,28 @@ int SWIG_main(int argc, char *argv[], const TargetLanguageModule *tlm) {
Preprocessor_define("SWIG 1", 0); Preprocessor_define("SWIG 1", 0);
Preprocessor_define("__STDC__ 1", 0); Preprocessor_define("__STDC__ 1", 0);
// Define __cplusplus to the C++98 value, but only if it's not already if (CPlusPlus) {
// defined so the user to override with e.g. -D__cplusplus=202002L // Default to C++98.
if (CPlusPlus && !Preprocessor_defined("__cplusplus")) if (!stdcpp_define) stdcpp_define = "__cplusplus 199711L";
Preprocessor_define("__cplusplus 199711L", 0); Preprocessor_define(stdcpp_define, 0);
} else {
if (stdcpp_define) {
Printf(stderr, "Option -std=c++XX was used without -c++\n");
Exit(EXIT_FAILURE);
}
}
if (!CPlusPlus) {
// Default to C90 which didn't define __STDC_VERSION__.
if (stdc_define) {
Preprocessor_define(stdc_define, 0);
}
} else {
if (stdc_define) {
Printf(stderr, "Option -std=cXX was used with -c++\n");
Exit(EXIT_FAILURE);
}
}
String *vers = Swig_package_version_hex(); String *vers = Swig_package_version_hex();
Preprocessor_define(vers, 0); Preprocessor_define(vers, 0);