Commit 653ce3550d18a07194a4c3bb9b4a3d260ed842cd

Authored by Jay Berkenbilt
1 parent a1fd00e7

Require C++-11

Includes updates to m4/ax_cxx_compile_stdcxx.m4 to make it work with
msvc, which supports C++-11 with no flags but doesn't set __cplusplus
to a recent value.
README.md
... ... @@ -27,9 +27,9 @@ Versions of qpdf prior to version 7 were released under the terms of version 2.0
27 27  
28 28 # Prerequisites
29 29  
30   -QPDF depends on the external libraries [zlib](http://www.zlib.net/) and [jpeg](http://www.ijg.org/files/). The [libjpeg-turbo](https://libjpeg-turbo.org/) library is also known to work since it is compatible with the regular jpeg library, and QPDF doesn't use any interfaces that aren't present in the straight jpeg8 API. These are part of every Linux distribution and are readily available. Download information appears in the documentation. For Windows, you can download pre-built binary versions of these libraries for some compilers; see [README-windows.md](README-windows.md) for additional details.
  30 +QPDF requires a C++ compiler that supports C++-11.
31 31  
32   -QPDF requires a C++ compiler that works with STL. Your compiler must also support `long long`. Almost all modern compilers do. If you are trying to port qpdf to a compiler that doesn't support `long long`, you could change all occurrences of `long long` to `long` in the source code, noting that this would break binary compatibility with other builds of qpdf. Doing so would certainly prevent qpdf from working with files larger than 2 GB, but remaining functionality would most likely work fine. If you built qpdf this way and it passed its test suite with large file support disabled, you could be confident that you had an otherwise working qpdf.
  32 +QPDF depends on the external libraries [zlib](http://www.zlib.net/) and [jpeg](http://www.ijg.org/files/). The [libjpeg-turbo](https://libjpeg-turbo.org/) library is also known to work since it is compatible with the regular jpeg library, and QPDF doesn't use any interfaces that aren't present in the straight jpeg8 API. These are part of every Linux distribution and are readily available. Download information appears in the documentation. For Windows, you can download pre-built binary versions of these libraries for some compilers; see [README-windows.md](README-windows.md) for additional details.
33 33  
34 34 # Licensing terms of embedded software
35 35  
... ...
... ... @@ -7,18 +7,15 @@ Fuzz Errors
7 7 * Problems inside the jpeg library: 15470, 15751, 18633
8 8 * Timeout: 17630
9 9  
10   -C++-11 (for qpdf 10)
11   -====================
12   -
13   -* Consider requiring C++-11 for qpdf 10.
14   -
15   -* My c++11 branch adds autoconf tests to require C++-11 and
16   - re-implements PointerHolder so that it is interchangeable with
17   - std::shared_ptr. It is not actually possible to just replace
18   - PointerHolder with std::shared_ptr for two reasons: there is no
19   - automatic creation of std::shared_ptr<T> from T* like there is for
20   - PointerHolder, which breaks some code, and also there is no
21   - automatic conversion from something like
  10 +C++-11
  11 +======
  12 +
  13 +* My c++11 branch adds re-implements PointerHolder so that it is
  14 + interchangeable with std::shared_ptr. It is not actually possible to
  15 + just replace PointerHolder with std::shared_ptr for two reasons:
  16 + there is no automatic creation of std::shared_ptr<T> from T* like
  17 + there is for PointerHolder, which breaks some code, and also there
  18 + is no automatic conversion from something like
22 19 std::vector<PointerHolder<T>> to std::vector<std::shared_ptr<T>>. It
23 20 may be a good idea to replace PointerHolder with std::shared_ptr in
24 21 the API even if it requires some work for the developer, but even if
... ...
aclocal.m4
... ... @@ -12,6 +12,7 @@
12 12 # PARTICULAR PURPOSE.
13 13  
14 14 m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
  15 +m4_include([m4/ax_cxx_compile_stdcxx.m4])
15 16 m4_include([m4/ax_random_device.m4])
16 17 m4_include([m4/libtool.m4])
17 18 m4_include([m4/ltoptions.m4])
... ...
autofiles.sums
1   -098c86e890756ed699b0a31a8a92910bb65c88656b77f6aa986cd644fa7c7ab1 configure.ac
2   -9c264dc3fac489fd0178d3fa9fd29d5b0ccd37d561e926ef449fa01d99abded7 aclocal.m4
3   -79ee40c3867f4162a847c005a73a5e388e3882f71dd185d39d9ddf0312133086 libqpdf/qpdf/qpdf-config.h.in
4   -8c8779c2182b0c4e85d5fc580024601e45b3a2ad95dd00234aaa63d62e491f0c m4/ax_cxx_compile_stdcxx.m4
  1 +384fa974656199e43cb904500c6013c3c53cb768b26eedb26440305960e07479 configure.ac
  2 +d3f9ee6f6f0846888d9a10fd3dad2e4b1258be84205426cf04d7cef02d61dad7 aclocal.m4
  3 +6bfabf45d5b7cee4160caacc34feed7c36207605c913d973b391ab13f637bc64 libqpdf/qpdf/qpdf-config.h.in
  4 +5297971a0ef90bcd5563eb3f7127a032bb76d3ae2af7258bf13479caf8983a60 m4/ax_cxx_compile_stdcxx.m4
5 5 35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4
6 6 37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4
7 7 e77ebba8361b36f14b4d0927173a034b98c5d05049697a9ded84d85eb99a7990 m4/ltoptions.m4
... ...
configure
... ... @@ -699,6 +699,7 @@ AS
699 699 EGREP
700 700 GREP
701 701 CPP
  702 +HAVE_CXX11
702 703 ac_ct_CXX
703 704 CXXFLAGS
704 705 CXX
... ... @@ -4068,6 +4069,367 @@ ac_link=&#39;$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
4068 4069 ac_compiler_gnu=$ac_cv_c_compiler_gnu
4069 4070  
4070 4071  
  4072 + ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=true
  4073 + ac_ext=cpp
  4074 +ac_cpp='$CXXCPP $CPPFLAGS'
  4075 +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
  4076 +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
  4077 +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
  4078 + ac_success=no
  4079 +
  4080 +
  4081 +
  4082 + if test x$ac_success = xno; then
  4083 + for alternative in ${ax_cxx_compile_alternatives}; do
  4084 + for switch in "" -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
  4085 + cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
  4086 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
  4087 +$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
  4088 +if eval \${$cachevar+:} false; then :
  4089 + $as_echo_n "(cached) " >&6
  4090 +else
  4091 + ac_save_CXX="$CXX"
  4092 + CXX="$CXX $switch"
  4093 + cat confdefs.h - <<_ACEOF >conftest.$ac_ext
  4094 +/* end confdefs.h. */
  4095 +
  4096 +
  4097 +// If the compiler admits that it is not ready for C++11, why torture it?
  4098 +// Hopefully, this will speed up the test.
  4099 +
  4100 +#ifndef __cplusplus
  4101 +
  4102 +#error "This is not a C++ compiler"
  4103 +
  4104 +#elif __cplusplus < 201103L && ! defined(_MSC_VER)
  4105 +
  4106 +#error "This is not a C++11 compiler"
  4107 +
  4108 +#else
  4109 +
  4110 +namespace cxx11
  4111 +{
  4112 +
  4113 + namespace test_static_assert
  4114 + {
  4115 +
  4116 + template <typename T>
  4117 + struct check
  4118 + {
  4119 + static_assert(sizeof(int) <= sizeof(T), "not big enough");
  4120 + };
  4121 +
  4122 + }
  4123 +
  4124 + namespace test_final_override
  4125 + {
  4126 +
  4127 + struct Base
  4128 + {
  4129 + virtual ~Base() {}
  4130 + virtual void f() {}
  4131 + };
  4132 +
  4133 + struct Derived : public Base
  4134 + {
  4135 + virtual ~Derived() override {}
  4136 + virtual void f() override {}
  4137 + };
  4138 +
  4139 + }
  4140 +
  4141 + namespace test_double_right_angle_brackets
  4142 + {
  4143 +
  4144 + template < typename T >
  4145 + struct check {};
  4146 +
  4147 + typedef check<void> single_type;
  4148 + typedef check<check<void>> double_type;
  4149 + typedef check<check<check<void>>> triple_type;
  4150 + typedef check<check<check<check<void>>>> quadruple_type;
  4151 +
  4152 + }
  4153 +
  4154 + namespace test_decltype
  4155 + {
  4156 +
  4157 + int
  4158 + f()
  4159 + {
  4160 + int a = 1;
  4161 + decltype(a) b = 2;
  4162 + return a + b;
  4163 + }
  4164 +
  4165 + }
  4166 +
  4167 + namespace test_type_deduction
  4168 + {
  4169 +
  4170 + template < typename T1, typename T2 >
  4171 + struct is_same
  4172 + {
  4173 + static const bool value = false;
  4174 + };
  4175 +
  4176 + template < typename T >
  4177 + struct is_same<T, T>
  4178 + {
  4179 + static const bool value = true;
  4180 + };
  4181 +
  4182 + template < typename T1, typename T2 >
  4183 + auto
  4184 + add(T1 a1, T2 a2) -> decltype(a1 + a2)
  4185 + {
  4186 + return a1 + a2;
  4187 + }
  4188 +
  4189 + int
  4190 + test(const int c, volatile int v)
  4191 + {
  4192 + static_assert(is_same<int, decltype(0)>::value == true, "");
  4193 + static_assert(is_same<int, decltype(c)>::value == false, "");
  4194 + static_assert(is_same<int, decltype(v)>::value == false, "");
  4195 + auto ac = c;
  4196 + auto av = v;
  4197 + auto sumi = ac + av + 'x';
  4198 + auto sumf = ac + av + 1.0;
  4199 + static_assert(is_same<int, decltype(ac)>::value == true, "");
  4200 + static_assert(is_same<int, decltype(av)>::value == true, "");
  4201 + static_assert(is_same<int, decltype(sumi)>::value == true, "");
  4202 + static_assert(is_same<int, decltype(sumf)>::value == false, "");
  4203 + static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
  4204 + return (sumf > 0.0) ? sumi : add(c, v);
  4205 + }
  4206 +
  4207 + }
  4208 +
  4209 + namespace test_noexcept
  4210 + {
  4211 +
  4212 + int f() { return 0; }
  4213 + int g() noexcept { return 0; }
  4214 +
  4215 + static_assert(noexcept(f()) == false, "");
  4216 + static_assert(noexcept(g()) == true, "");
  4217 +
  4218 + }
  4219 +
  4220 + namespace test_constexpr
  4221 + {
  4222 +
  4223 + template < typename CharT >
  4224 + unsigned long constexpr
  4225 + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
  4226 + {
  4227 + return *s ? strlen_c_r(s + 1, acc + 1) : acc;
  4228 + }
  4229 +
  4230 + template < typename CharT >
  4231 + unsigned long constexpr
  4232 + strlen_c(const CharT *const s) noexcept
  4233 + {
  4234 + return strlen_c_r(s, 0UL);
  4235 + }
  4236 +
  4237 + static_assert(strlen_c("") == 0UL, "");
  4238 + static_assert(strlen_c("1") == 1UL, "");
  4239 + static_assert(strlen_c("example") == 7UL, "");
  4240 + static_assert(strlen_c("another\0example") == 7UL, "");
  4241 +
  4242 + }
  4243 +
  4244 + namespace test_rvalue_references
  4245 + {
  4246 +
  4247 + template < int N >
  4248 + struct answer
  4249 + {
  4250 + static constexpr int value = N;
  4251 + };
  4252 +
  4253 + answer<1> f(int&) { return answer<1>(); }
  4254 + answer<2> f(const int&) { return answer<2>(); }
  4255 + answer<3> f(int&&) { return answer<3>(); }
  4256 +
  4257 + void
  4258 + test()
  4259 + {
  4260 + int i = 0;
  4261 + const int c = 0;
  4262 + static_assert(decltype(f(i))::value == 1, "");
  4263 + static_assert(decltype(f(c))::value == 2, "");
  4264 + static_assert(decltype(f(0))::value == 3, "");
  4265 + }
  4266 +
  4267 + }
  4268 +
  4269 + namespace test_uniform_initialization
  4270 + {
  4271 +
  4272 + struct test
  4273 + {
  4274 + static const int zero {};
  4275 + static const int one {1};
  4276 + };
  4277 +
  4278 + static_assert(test::zero == 0, "");
  4279 + static_assert(test::one == 1, "");
  4280 +
  4281 + }
  4282 +
  4283 + namespace test_lambdas
  4284 + {
  4285 +
  4286 + void
  4287 + test1()
  4288 + {
  4289 + auto lambda1 = [](){};
  4290 + auto lambda2 = lambda1;
  4291 + lambda1();
  4292 + lambda2();
  4293 + }
  4294 +
  4295 + int
  4296 + test2()
  4297 + {
  4298 + auto a = [](int i, int j){ return i + j; }(1, 2);
  4299 + auto b = []() -> int { return '0'; }();
  4300 + auto c = [=](){ return a + b; }();
  4301 + auto d = [&](){ return c; }();
  4302 + auto e = [a, &b](int x) mutable {
  4303 + const auto identity = [](int y){ return y; };
  4304 + for (auto i = 0; i < a; ++i)
  4305 + a += b--;
  4306 + return x + identity(a + b);
  4307 + }(0);
  4308 + return a + b + c + d + e;
  4309 + }
  4310 +
  4311 + int
  4312 + test3()
  4313 + {
  4314 + const auto nullary = [](){ return 0; };
  4315 + const auto unary = [](int x){ return x; };
  4316 + using nullary_t = decltype(nullary);
  4317 + using unary_t = decltype(unary);
  4318 + const auto higher1st = [](nullary_t f){ return f(); };
  4319 + const auto higher2nd = [unary](nullary_t f1){
  4320 + return [unary, f1](unary_t f2){ return f2(unary(f1())); };
  4321 + };
  4322 + return higher1st(nullary) + higher2nd(nullary)(unary);
  4323 + }
  4324 +
  4325 + }
  4326 +
  4327 + namespace test_variadic_templates
  4328 + {
  4329 +
  4330 + template <int...>
  4331 + struct sum;
  4332 +
  4333 + template <int N0, int... N1toN>
  4334 + struct sum<N0, N1toN...>
  4335 + {
  4336 + static constexpr auto value = N0 + sum<N1toN...>::value;
  4337 + };
  4338 +
  4339 + template <>
  4340 + struct sum<>
  4341 + {
  4342 + static constexpr auto value = 0;
  4343 + };
  4344 +
  4345 + static_assert(sum<>::value == 0, "");
  4346 + static_assert(sum<1>::value == 1, "");
  4347 + static_assert(sum<23>::value == 23, "");
  4348 + static_assert(sum<1, 2>::value == 3, "");
  4349 + static_assert(sum<5, 5, 11>::value == 21, "");
  4350 + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
  4351 +
  4352 + }
  4353 +
  4354 + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
  4355 + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
  4356 + // because of this.
  4357 + namespace test_template_alias_sfinae
  4358 + {
  4359 +
  4360 + struct foo {};
  4361 +
  4362 + template<typename T>
  4363 + using member = typename T::member_type;
  4364 +
  4365 + template<typename T>
  4366 + void func(...) {}
  4367 +
  4368 + template<typename T>
  4369 + void func(member<T>*) {}
  4370 +
  4371 + void test();
  4372 +
  4373 + void test() { func<foo>(0); }
  4374 +
  4375 + }
  4376 +
  4377 +} // namespace cxx11
  4378 +
  4379 +#endif // __cplusplus >= 201103L
  4380 +
  4381 +
  4382 +
  4383 +_ACEOF
  4384 +if ac_fn_cxx_try_compile "$LINENO"; then :
  4385 + eval $cachevar=yes
  4386 +else
  4387 + eval $cachevar=no
  4388 +fi
  4389 +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
  4390 + CXX="$ac_save_CXX"
  4391 +fi
  4392 +eval ac_res=\$$cachevar
  4393 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
  4394 +$as_echo "$ac_res" >&6; }
  4395 + if eval test x\$$cachevar = xyes; then
  4396 + CXX="$CXX $switch"
  4397 + if test -n "$CXXCPP" ; then
  4398 + CXXCPP="$CXXCPP $switch"
  4399 + fi
  4400 + ac_success=yes
  4401 + break
  4402 + fi
  4403 + done
  4404 + if test x$ac_success = xyes; then
  4405 + break
  4406 + fi
  4407 + done
  4408 + fi
  4409 + ac_ext=c
  4410 +ac_cpp='$CPP $CPPFLAGS'
  4411 +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
  4412 +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
  4413 +ac_compiler_gnu=$ac_cv_c_compiler_gnu
  4414 +
  4415 + if test x$ax_cxx_compile_cxx11_required = xtrue; then
  4416 + if test x$ac_success = xno; then
  4417 + as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
  4418 + fi
  4419 + fi
  4420 + if test x$ac_success = xno; then
  4421 + HAVE_CXX11=0
  4422 + { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
  4423 +$as_echo "$as_me: No compiler with C++11 support was found" >&6;}
  4424 + else
  4425 + HAVE_CXX11=1
  4426 +
  4427 +$as_echo "#define HAVE_CXX11 1" >>confdefs.h
  4428 +
  4429 + fi
  4430 +
  4431 +
  4432 +
4071 4433 ac_ext=c
4072 4434 ac_cpp='$CPP $CPPFLAGS'
4073 4435 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
... ... @@ -7903,7 +8265,6 @@ done
7903 8265  
7904 8266  
7905 8267  
7906   -
7907 8268 func_stripname_cnf ()
7908 8269 {
7909 8270 case $2 in
... ...
configure.ac
... ... @@ -36,6 +36,7 @@ fi
36 36 AC_PROG_CC
37 37 AC_PROG_CC_C99
38 38 AC_PROG_CXX
  39 +AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory])
39 40 AC_HEADER_STDC
40 41 LT_INIT([win32-dll])
41 42  
... ...
libqpdf/qpdf/qpdf-config.h.in
... ... @@ -3,6 +3,9 @@
3 3 /* Whether to avoid use of HANDLE in Windows */
4 4 #undef AVOID_WINDOWS_HANDLE
5 5  
  6 +/* define if the compiler supports basic C++11 syntax */
  7 +#undef HAVE_CXX11
  8 +
6 9 /* Define to 1 if you have the <dlfcn.h> header file. */
7 10 #undef HAVE_DLFCN_H
8 11  
... ...
m4/ax_cxx_compile_stdcxx.m4 100755 → 100644
... ... @@ -92,7 +92,7 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
92 92 dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
93 93 dnl Cray's crayCC needs "-h std=c++11"
94 94 for alternative in ${ax_cxx_compile_alternatives}; do
95   - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
  95 + for switch in "" -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
96 96 cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
97 97 AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
98 98 $cachevar,
... ... @@ -165,7 +165,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
165 165  
166 166 #error "This is not a C++ compiler"
167 167  
168   -#elif __cplusplus < 201103L
  168 +#elif __cplusplus < 201103L && ! defined(_MSC_VER)
169 169  
170 170 #error "This is not a C++11 compiler"
171 171  
... ... @@ -456,7 +456,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
456 456  
457 457 #error "This is not a C++ compiler"
458 458  
459   -#elif __cplusplus < 201402L
  459 +#elif __cplusplus < 201402L && ! defined(_MSC_VER)
460 460  
461 461 #error "This is not a C++14 compiler"
462 462  
... ... @@ -580,7 +580,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
580 580  
581 581 #error "This is not a C++ compiler"
582 582  
583   -#elif __cplusplus < 201703L
  583 +#elif __cplusplus < 201703L && ! defined(_MSC_VER)
584 584  
585 585 #error "This is not a C++17 compiler"
586 586  
... ...