diff options
author | Lukas Larsson <lukas@erlang.org> | 2021-01-13 10:29:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-13 10:29:44 +0100 |
commit | 8cc56ab98c935168c7935ab564eb2c60f907406c (patch) | |
tree | 0f589d034823354f81ddafdc4db2c9cad249f857 | |
parent | f71dbfb082d8db8cde8b26737ada2493e4eed3df (diff) | |
parent | ab920443004e1ac0d56140035514515253864007 (diff) | |
download | erlang-8cc56ab98c935168c7935ab564eb2c60f907406c.tar.gz |
Merge pull request #2872 from garazdawi/lukas/fix-configure-werror/OTP-17105
Add -Werror to github actions C/C++ compilation
-rw-r--r-- | .github/dockerfiles/Dockerfile.32-bit | 8 | ||||
-rw-r--r-- | .github/dockerfiles/Dockerfile.64-bit | 8 | ||||
-rw-r--r-- | .github/dockerfiles/Dockerfile.cross-compile | 32 | ||||
-rw-r--r-- | .github/dockerfiles/Dockerfile.ubuntu-base | 2 | ||||
-rwxr-xr-x | .github/scripts/init-pre-release.sh | 7 | ||||
-rw-r--r-- | .github/workflows/main.yaml | 19 | ||||
-rw-r--r-- | erts/configure.in | 39 | ||||
-rw-r--r-- | erts/emulator/Makefile.in | 9 | ||||
-rw-r--r-- | erts/emulator/beam/jit/beam_asm.hpp | 4 | ||||
-rw-r--r-- | erts/emulator/beam/packet_parser.c | 9 | ||||
-rw-r--r-- | erts/emulator/beam/sys.h | 80 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 43 | ||||
-rw-r--r-- | erts/emulator/nifs/common/prim_socket_nif.c | 2 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_int.h | 22 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_util.c | 3 | ||||
-rw-r--r-- | erts/emulator/nifs/common/socket_util.h | 9 | ||||
-rw-r--r-- | lib/crypto/c_src/crypto_callback.c | 21 | ||||
-rw-r--r-- | lib/odbc/c_src/odbcserver.c | 83 | ||||
-rw-r--r-- | lib/wx/configure.in | 6 |
19 files changed, 271 insertions, 135 deletions
diff --git a/.github/dockerfiles/Dockerfile.32-bit b/.github/dockerfiles/Dockerfile.32-bit index 8d955a46e4..fd64b40c4e 100644 --- a/.github/dockerfiles/Dockerfile.32-bit +++ b/.github/dockerfiles/Dockerfile.32-bit @@ -12,7 +12,13 @@ RUN cd /buildroot && tar -xzf ./otp.tar.gz WORKDIR /buildroot/otp/ -RUN ./configure --prefix=/otp && make && make install && \ +ENV CFLAGS="-O2 -g -Werror" + +## Configure, check that no application are disabled, then make and then build doc chunks +RUN ./configure --prefix=/otp && \ + if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi + +RUN make && make install && \ make install-docs DOC_TARGETS=chunks RUN TESTSUITE_ROOT=/tests ./otp_build tests diff --git a/.github/dockerfiles/Dockerfile.64-bit b/.github/dockerfiles/Dockerfile.64-bit index c651cbc618..2074b364e2 100644 --- a/.github/dockerfiles/Dockerfile.64-bit +++ b/.github/dockerfiles/Dockerfile.64-bit @@ -15,7 +15,13 @@ RUN cd /buildroot && tar -xzf ./otp.tar.gz WORKDIR /buildroot/otp/ -RUN ./configure --prefix=/otp && make && make install +ENV CC=clang CXX=clang++ \ + CFLAGS="-O2 -g -Werror" + +## Configure, check that no application are disabled and then make +RUN ./configure --prefix=/otp && \ + if cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi && \ + make && make install RUN TESTSUITE_ROOT=/tests ./otp_build tests diff --git a/.github/dockerfiles/Dockerfile.cross-compile b/.github/dockerfiles/Dockerfile.cross-compile index 868f8beed1..43aeedfe96 100644 --- a/.github/dockerfiles/Dockerfile.cross-compile +++ b/.github/dockerfiles/Dockerfile.cross-compile @@ -9,38 +9,48 @@ ARG HOST_TRIP=x86_64-linux-gnu ARG MAKEFLAGS=-j4 ENV MAKEFLAGS=$MAKEFLAGS \ ERLC_USE_SERVER=yes \ - ERL_TOP=/buildroot/otp + ERL_TOP=/buildroot/bootstrap/otp + +WORKDIR /buildroot/bootstrap ARG ARCHIVE=./otp.tar.gz COPY $ARCHIVE /buildroot/otp.tar.gz -RUN cd /buildroot && tar xzf ./otp.tar.gz - -WORKDIR /buildroot/otp/ +RUN tar xzf ../otp.tar.gz ## Build the bootstrap system -RUN ./configure && make && make install +RUN cd $ERL_TOP && CFLAGS="-Wall -O2 -g" ./configure && make && make install ## Build pre-build tar ball -RUN scripts/build-otp-tar -o /buildroot/otp_clean_src.tar.gz /buildroot/otp_src.tar.gz -b /buildroot/otp/ /buildroot/otp.tar.gz +RUN cd $ERL_TOP && scripts/build-otp-tar -o /buildroot/otp_clean_src.tar.gz /buildroot/otp_src.tar.gz -b /buildroot/bootstrap/otp/ /buildroot/otp.tar.gz ## Prepare for a new build using pre-built tar ball -RUN cd .. && rm -rf otp && tar -xzf ./otp_src.tar.gz +RUN cd ../ && tar -xzf ./otp_src.tar.gz ENV HOST=$HOST_TRIP \ CC=$HOST_TRIP-gcc \ + CPPFLAGS="--sysroot=/buildroot/sysroot" \ + CFLAGS="--sysroot=/buildroot/sysroot -O2 -g -Werror" \ CPP=$HOST_TRIP-cpp \ CXX=$HOST_TRIP-g++ \ LD=$CC \ - DED_LDFLAGS="-shared -Wl,-Bsymbolic" \ + LD_FLAGS="--sysroot=/buildroot/sysroot" \ + DED_CFLAGS="$CFLAGS" \ + DED_LDFLAGS="$LDFLAGS -shared -Wl,-Bsymbolic" \ RANLIB=$HOST_TRIP-ranlib \ AR=$HOST_TRIP-ar \ - erl_xcomp_sysroot=/buildroot/sysroot + erl_xcomp_sysroot=/buildroot/sysroot \ + ERL_TOP=/buildroot/otp + +WORKDIR /buildroot/otp ## Build the cross system -RUN ./configure --prefix=/otp/ --host=$HOST --build=`erts/autoconf/config.guess` && \ - make && make install +RUN ./configure --prefix=/otp/ --host=$HOST --build=`erts/autoconf/config.guess` +RUN OTP_SMALL_BUILD=true V=1 make + +RUN make odbc && make install ## Build the cross tests +ENV CFLAGS="--sysroot=/buildroot/sysroot -O2 -g" RUN ./otp_build tests RUN cd release/tests/test_server && \ erl -sname test@docker -noshell -eval "ts:install([{cross,\"yes\"},{crossflags,[{\"host\",\"$HOST\"}]},{crossroot,\"/$ERL_TOP\"}])." -s ts compile_testcases -s init stop diff --git a/.github/dockerfiles/Dockerfile.ubuntu-base b/.github/dockerfiles/Dockerfile.ubuntu-base index a93c8a28f0..fbfe2470c7 100644 --- a/.github/dockerfiles/Dockerfile.ubuntu-base +++ b/.github/dockerfiles/Dockerfile.ubuntu-base @@ -9,5 +9,5 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get -y upgrade && \ - apt-get install -y build-essential m4 autoconf fop xsltproc clang-format \ + apt-get install -y build-essential m4 autoconf fop xsltproc clang clang-format \ default-jdk libxml2-utils $INSTALL_LIBS diff --git a/.github/scripts/init-pre-release.sh b/.github/scripts/init-pre-release.sh index 97378a0978..f000b250fe 100755 --- a/.github/scripts/init-pre-release.sh +++ b/.github/scripts/init-pre-release.sh @@ -12,7 +12,10 @@ find . -name config.h.in | xargs git add -f find . -name config.guess | xargs git add -f find . -name config.sub | xargs git add -f find . -name install-sh | xargs git add -f -git config user.email "you@example.com" -git config user.name "Your Name" +if ! git config user.name; then + git config user.email "you@example.com" + git config user.name "Your Name" +fi git commit --no-verify -m 'Add generated configure files' git archive --prefix otp/ -o otp_src.tar.gz HEAD +git reset --hard HEAD~1 diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 13c5d729f4..5e64d6fb9a 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -52,6 +52,25 @@ jobs: ## the base debian image. - name: Docker login run: docker login https://docker.pkg.github.com -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} + - name: Build base image + run: | + BASE_TAG=$(grep "^FROM" .github/dockerfiles/Dockerfile.${{ matrix.type }} | head -1 | awk '{print $2}') + docker pull "${BASE_TAG}" + case "${BASE_TAG}" in + */i386-debian-base) + docker build -t "${BASE_TAG}" \ + --build-arg BASE=i386/debian -f .github/dockerfiles/Dockerfile.debian-base . + ;; + */debian-base) + docker build -t "${BASE_TAG}" \ + -f .github/dockerfiles/Dockerfile.debian-base . + ;; + */ubuntu-base) + docker build -t "${BASE_TAG}" \ + -f .github/dockerfiles/Dockerfile.ubuntu-base . + ;; + esac + - name: Build ${{ matrix.type }} image run: | docker build -t otp --build-arg ARCHIVE=otp_src.tar.gz \ diff --git a/erts/configure.in b/erts/configure.in index 09b4c0473d..70dceabcfe 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -26,6 +26,15 @@ AC_PREREQ(2.59) LM_PRECIOUS_VARS +dnl We check if -Werror was given on command line and if so +dnl we disable it for the configure and only use it when +dnl actually building erts +no_werror_CFLAGS=$(echo "$CFLAGS" | sed 's/-Werror\([[^=]]\|$\)/ /g') +if test "$CFLAGS" != "$no_werror_CFLAGS"; then + CFLAGS="$no_werror_CFLAGS" + WERRORFLAGS=-Werror +fi + dnl How to set srcdir absolute is taken from the GNU Emacs distribution #### Make srcdir absolute, if it isn't already. It's important to #### avoid running the path through pwd unnecessary, since pwd can @@ -570,7 +579,7 @@ if test "x$GCC" = xyes; then LM_TRY_ENABLE_CFLAG([-fno-common], [CFLAGS]) else WFLAGS="" - WERRORFLAGS="" + WERRORFLAGS=${WERRORFLAGS:-""} fi AC_MSG_CHECKING([C99 support]) @@ -3512,6 +3521,29 @@ AH_BOTTOM([ #endif /* __ERTS_CONFIG_H__ */ ]) +dnl ---------------------------------------------------------------------- +dnl Check for log2 +dnl ---------------------------------------------------------------------- +AC_CHECK_FUNCS([log2]) + +dnl ---------------------------------------------------------------------- +dnl Check for GCC diagnostic ignored "-Waddress-of-packed-member" +dnl ---------------------------------------------------------------------- +saved_CFLAGS="$CFLAGS" +CFLAGS="-Werror $CFLAGS" +AC_TRY_COMPILE([], + [_Pragma("GCC diagnostic push") + _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") + _Pragma("GCC diagnostic pop") + ], + AC_DEFINE(HAVE_GCC_DIAG_IGNORE_WADDRESS_OF_PACKED_MEMBER,[1], + [define if compiler support _Pragma('GCC diagnostic ignored '-Waddress-of-packed-member'')])) +CFLAGS="$saved_CFLAGS" + +dnl ---------------------------------------------------------------------- +dnl Enable any -Werror flags +dnl ---------------------------------------------------------------------- + if test "x$GCC" = xyes; then CFLAGS="$WERRORFLAGS $CFLAGS" fi @@ -3537,11 +3569,6 @@ LDFLAGS="$LDFLAGS $sanitizers" ]) dnl ---------------------------------------------------------------------- -dnl Check for log2 -dnl ---------------------------------------------------------------------- -AC_CHECK_FUNCS([log2]) - -dnl ---------------------------------------------------------------------- dnl Output the result. dnl ---------------------------------------------------------------------- diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index fcc302e4c8..726845e7b8 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -843,8 +843,8 @@ $(OBJDIR)/%.o: nifs/$(ERLANG_OSTYPE)/%.c # included before any other directives, including other #includes. # ASMJIT_FLAGS=-DASMJIT_EMBED=1 -DASMJIT_NO_BUILDER=1 -DASMJIT_NO_DEPRECATED=1 -DASMJIT_STATIC=1 -ASMJIT_PCH_OBJ=$(TTF_DIR)/asmjit/asmjit.h.gch -ASMJIT_PCH_SRC=$(TTF_DIR)/asmjit/asmjit.h +ASMJIT_PCH_OBJ=$(TTF_DIR)/asmjit/asmjit.hpp.gch +ASMJIT_PCH_SRC=$(TTF_DIR)/asmjit/asmjit.hpp $(OBJDIR)/%.o: beam/jit/%.cpp beam/jit/beam_asm.hpp $(ASMJIT_PCH_OBJ) $(V_CXX) $(ASMJIT_FLAGS) $(INCLUDES) \ @@ -865,6 +865,8 @@ $(ASMJIT_PCH_OBJ): $(ASMJIT_PCH_SRC) $(ASMJIT_TTF_H) beam/erl_bif_info.c ## We copy all asmjit headers into TTF_DIR in order for cross-compilation ## with pre-compiled header to work. +$(TTF_DIR)/asmjit/asmjit.hpp: asmjit/asmjit.h + $(V_at)cp $< $@ $(TTF_DIR)/asmjit/%.h: asmjit/%.h $(V_at)cp $< $@ @@ -1183,6 +1185,7 @@ SED_REPL_TTF_DIR=s|$(TTF_DIR)/|$$(TTF_DIR)/|g SED_REPL_ERL_TOP=s|\([ ]\)$(ERL_TOP)/|\1$$(ERL_TOP)/|g;s|^$(ERL_TOP)/|$$(ERL_TOP)/|g SED_REPL_POLL=s|$$(OBJDIR)/erl_poll.o|$$(OBJDIR)/erl_poll.o $$(OBJDIR)/erl_poll.flbk.o|g SED_REPL_TTF_COMP_FLAGS=s|\([^/]\)erl_compile_flags\.h|\1$$(TTF_DIR)/erl_compile_flags\.h|g +SED_ASMJIT_HPP_FLAGS=s|\([^/]\)asmjit/asmjit\.hpp|\1$$(TTF_DIR)/asmjit/asmjit\.hpp|g ifeq ($(TARGET),win32) #SED_PREFIX=$(SED_REPL_WIN_DRIVE); @@ -1197,7 +1200,7 @@ else SED_SUFFIX= endif -SED_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_O);$(SED_REPL_TTF_DIR);$(SED_REPL_ERL_TOP)$(SED_SUFFIX);$(SED_REPL_TTF_COMP_FLAGS)' +SED_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_O);$(SED_REPL_TTF_DIR);$(SED_REPL_ERL_TOP)$(SED_SUFFIX);$(SED_REPL_TTF_COMP_FLAGS);$(SED_ASMJIT_HPP_FLAGS)' SED_DEPEND_ZLIB=sed '$(SED_PREFIX)$(SED_REPL_O_ZLIB)' BEAM_SRC=$(wildcard beam/*.c) diff --git a/erts/emulator/beam/jit/beam_asm.hpp b/erts/emulator/beam/jit/beam_asm.hpp index 2c0fe9851f..bc1f13750a 100644 --- a/erts/emulator/beam/jit/beam_asm.hpp +++ b/erts/emulator/beam/jit/beam_asm.hpp @@ -23,7 +23,9 @@ #include <unordered_map> #include <map> -#include <asmjit/asmjit.h> +#ifndef ASMJIT_ASMJIT_H_INCLUDED +# include <asmjit/asmjit.hpp> +#endif extern "C" { diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c index 8f24725326..d3f02d55c8 100644 --- a/erts/emulator/beam/packet_parser.c +++ b/erts/emulator/beam/packet_parser.c @@ -39,15 +39,6 @@ # define DEBUGF(X) printf X #endif -#define get_int24(s) ((((unsigned char*) (s))[0] << 16) | \ - (((unsigned char*) (s))[1] << 8) | \ - (((unsigned char*) (s))[2])) - -#define get_little_int32(s) ((((unsigned char*) (s))[3] << 24) | \ - (((unsigned char*) (s))[2] << 16) | \ - (((unsigned char*) (s))[1] << 8) | \ - (((unsigned char*) (s))[0])) - #if !defined(__WIN32__) && !defined(HAVE_STRNCASECMP) #define STRNCASECMP my_strncasecmp diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 789c4b0ca9..1ffc7f5028 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -1160,60 +1160,66 @@ ERTS_GLB_INLINE size_t sys_strlen(const char *s) /* Standard set of integer macros .. */ -#define get_int64(s) (((Uint64)(((unsigned char*) (s))[0]) << 56) | \ - (((Uint64)((unsigned char*) (s))[1]) << 48) | \ - (((Uint64)((unsigned char*) (s))[2]) << 40) | \ - (((Uint64)((unsigned char*) (s))[3]) << 32) | \ - (((Uint64)((unsigned char*) (s))[4]) << 24) | \ - (((Uint64)((unsigned char*) (s))[5]) << 16) | \ - (((Uint64)((unsigned char*) (s))[6]) << 8) | \ - (((Uint64)((unsigned char*) (s))[7]))) - -#define put_int64(i, s) do {((char*)(s))[0] = (char)((Sint64)(i) >> 56) & 0xff;\ - ((char*)(s))[1] = (char)((Sint64)(i) >> 48) & 0xff;\ - ((char*)(s))[2] = (char)((Sint64)(i) >> 40) & 0xff;\ - ((char*)(s))[3] = (char)((Sint64)(i) >> 32) & 0xff;\ - ((char*)(s))[4] = (char)((Sint64)(i) >> 24) & 0xff;\ - ((char*)(s))[5] = (char)((Sint64)(i) >> 16) & 0xff;\ - ((char*)(s))[6] = (char)((Sint64)(i) >> 8) & 0xff;\ - ((char*)(s))[7] = (char)((Sint64)(i)) & 0xff;\ +#define get_int64(s) (((Uint64)(((byte*) (s))[0]) << 56) | \ + (((Uint64)((byte*) (s))[1]) << 48) | \ + (((Uint64)((byte*) (s))[2]) << 40) | \ + (((Uint64)((byte*) (s))[3]) << 32) | \ + (((Uint64)((byte*) (s))[4]) << 24) | \ + (((Uint64)((byte*) (s))[5]) << 16) | \ + (((Uint64)((byte*) (s))[6]) << 8) | \ + (((Uint64)((byte*) (s))[7]))) + +#define put_int64(i, s) do {((byte*)(s))[0] = (byte)((Sint64)(i) >> 56) & 0xff;\ + ((byte*)(s))[1] = (byte)((Sint64)(i) >> 48) & 0xff;\ + ((byte*)(s))[2] = (byte)((Sint64)(i) >> 40) & 0xff;\ + ((byte*)(s))[3] = (byte)((Sint64)(i) >> 32) & 0xff;\ + ((byte*)(s))[4] = (byte)((Sint64)(i) >> 24) & 0xff;\ + ((byte*)(s))[5] = (byte)((Sint64)(i) >> 16) & 0xff;\ + ((byte*)(s))[6] = (byte)((Sint64)(i) >> 8) & 0xff;\ + ((byte*)(s))[7] = (byte)((Sint64)(i)) & 0xff;\ } while (0) /* Returns a signed int */ -#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \ - (((unsigned char*) (s))[1] << 16) | \ - (((unsigned char*) (s))[2] << 8) | \ - (((unsigned char*) (s))[3])) +#define get_int32(s) ((((byte*) (s))[0] << 24) | \ + (((byte*) (s))[1] << 16) | \ + (((byte*) (s))[2] << 8) | \ + (((byte*) (s))[3])) + +#define get_little_int32(s) ((((byte*) (s))[3] << 24) | \ + (((byte*) (s))[2] << 16) | \ + (((byte*) (s))[1] << 8) | \ + (((byte*) (s))[0])) #define get_uint32(s) ((Uint32)get_int32(s)) -#define put_int32(i, s) do {((char*)(s))[0] = (char)((i) >> 24) & 0xff; \ - ((char*)(s))[1] = (char)((i) >> 16) & 0xff; \ - ((char*)(s))[2] = (char)((i) >> 8) & 0xff; \ - ((char*)(s))[3] = (char)(i) & 0xff;} \ +#define put_int32(i, s) do {((byte*)(s))[0] = (byte)((i) >> 24) & 0xff; \ + ((byte*)(s))[1] = (byte)((i) >> 16) & 0xff; \ + ((byte*)(s))[2] = (byte)((i) >> 8) & 0xff; \ + ((byte*)(s))[3] = (byte)(i) & 0xff;} \ while (0) -#define get_int24(s) ((((unsigned char*) (s))[0] << 16) | \ - (((unsigned char*) (s))[1] << 8) | \ - (((unsigned char*) (s))[2])) +#define get_int24(s) ((((byte*) (s))[0] << 16) | \ + (((byte*) (s))[1] << 8) | \ + (((byte*) (s))[2])) + -#define put_int24(i, s) do {((char*)(s))[0] = (char)((i) >> 16) & 0xff; \ - ((char*)(s))[1] = (char)((i) >> 8) & 0xff; \ - ((char*)(s))[2] = (char)(i) & 0xff;} \ +#define put_int24(i, s) do {((byte*)(s))[0] = (byte)((i) >> 16) & 0xff; \ + ((byte*)(s))[1] = (byte)((i) >> 8) & 0xff; \ + ((byte*)(s))[2] = (byte)(i) & 0xff;} \ while (0) -#define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \ - (((unsigned char*) (s))[1])) +#define get_int16(s) ((((byte*) (s))[0] << 8) | \ + (((byte*) (s))[1])) -#define put_int16(i, s) do {((char*)(s))[0] = (char)((i) >> 8) & 0xff; \ - ((char*)(s))[1] = (char)(i) & 0xff;} \ +#define put_int16(i, s) do {((byte*)(s))[0] = (byte)((i) >> 8) & 0xff; \ + ((byte*)(s))[1] = (byte)(i) & 0xff;} \ while (0) -#define get_int8(s) ((((unsigned char*) (s))[0] )) +#define get_int8(s) ((((byte*) (s))[0] )) -#define put_int8(i, s) do {((unsigned char*)(s))[0] = (i) & 0xff;} while (0) +#define put_int8(i, s) do {((byte*)(s))[0] = (i) & 0xff;} while (0) /* * Use DEBUGF as you would use printf, but use double parentheses: diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 301a133d3a..c98d9cb756 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -82,6 +82,32 @@ /* All platforms fail on malloc errors. */ #define FATAL_MALLOC +/* The linux kernel sctp include files have an alignment bug + that causes warnings of this type to appear: + + drivers/common/inet_drv.c:3196:47: error: taking address of packed member of 'struct sctp_paddr_change' may result in an unaligned pointer value [-Werror=address-of-packed-member] + 3196 | i = load_inet_get_address(spec, i, desc, &sptr->spc_aaddr); + + So we need to suppress those, without disabling all warning + diagnostics of that type. + + See https://lore.kernel.org/patchwork/patch/1108122/ for the + patch that fixes this bug. In a few years we should be able to + remove this suppression. */ +#ifdef HAVE_GCC_DIAG_IGNORE_WADDRESS_OF_PACKED_MEMBER +#define PUSH_SUPPRESS_ADDRESS_OF_PACKED_MEMBER() \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"") \ + do { } while(0) +#define POP_SUPPRESS_ADDRESS_OF_PACKED_MEMBER() \ + _Pragma("GCC diagnostic pop") \ + do { } while(0) +#else +#define PUSH_SUPPRESS_ADDRESS_OF_PACKED_MEMBER() \ + do { } while(0) +#define POP_SUPPRESS_ADDRESS_OF_PACKED_MEMBER() \ + do { } while(0) +#endif #include "erl_driver.h" @@ -601,15 +627,6 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #include "packet_parser.h" -#define get_int24(s) ((((unsigned char*) (s))[0] << 16) | \ - (((unsigned char*) (s))[1] << 8) | \ - (((unsigned char*) (s))[2])) - -#define get_little_int32(s) ((((unsigned char*) (s))[3] << 24) | \ - (((unsigned char*) (s))[2] << 16) | \ - (((unsigned char*) (s))[1] << 8) | \ - (((unsigned char*) (s))[0])) - #if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) /* strnlen doesn't exist everywhere */ @@ -3193,7 +3210,9 @@ static int sctp_parse_async_event ASSERT(sptr->spc_length <= sz); /* No buffer overrun */ i = LOAD_ATOM (spec, i, am_sctp_paddr_change); + PUSH_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); i = load_inet_get_address(spec, i, desc, &sptr->spc_aaddr); + POP_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); switch (sptr->spc_state) { @@ -8150,7 +8169,9 @@ static int load_paddrinfo (ErlDrvTermData * spec, int i, { i = LOAD_ATOM (spec, i, am_sctp_paddrinfo); i = LOAD_ASSOC_ID (spec, i, pai->spinfo_assoc_id); + PUSH_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); i = load_inet_get_address(spec, i, desc, &pai->spinfo_address); + POP_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); switch(pai->spinfo_state) { case SCTP_ACTIVE: @@ -8670,7 +8691,9 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, ASSERT(0); } i = LOAD_ASSOC_ID (spec, i, sp.sspp_assoc_id); + PUSH_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); i = load_inet_get_address(spec, i, desc, &sp.sspp_addr); + POP_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); i = LOAD_TUPLE (spec, i, 3); i = LOAD_TUPLE (spec, i, 2); break; @@ -8730,7 +8753,9 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, i = LOAD_ATOM (spec, i, am_sctp_peer_addr_params); i = LOAD_ATOM (spec, i, am_sctp_paddrparams); i = LOAD_ASSOC_ID (spec, i, ap.spp_assoc_id); + PUSH_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); i = load_inet_get_address(spec, i, desc, &ap.spp_address); + POP_SUPPRESS_ADDRESS_OF_PACKED_MEMBER(); i = LOAD_INT (spec, i, ap.spp_hbinterval); i = LOAD_INT (spec, i, ap.spp_pathmaxrxt); diff --git a/erts/emulator/nifs/common/prim_socket_nif.c b/erts/emulator/nifs/common/prim_socket_nif.c index 3390f61e41..13916cbf06 100644 --- a/erts/emulator/nifs/common/prim_socket_nif.c +++ b/erts/emulator/nifs/common/prim_socket_nif.c @@ -4201,7 +4201,7 @@ ERL_NIF_TERM esock_command(ErlNifEnv* env, Uint16 cmd, ERL_NIF_TERM ecdata) break; default: - ESOCK_ASSERT(cmd == cmd); + ESOCK_ASSERT(FALSE && "cmd is unknown"); break; } diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h index 6fb25ee6a8..afe1b8e61a 100644 --- a/erts/emulator/nifs/common/socket_int.h +++ b/erts/emulator/nifs/common/socket_int.h @@ -66,6 +66,28 @@ #endif +/* Copied from sys.h + * In VC++, noreturn is a declspec that has to be before the types, + * but in GNUC it is an attribute to be placed between return type + * and function name, hence __decl_noreturn <types> __noreturn <function name> + * + * at some platforms (e.g. Android) __noreturn is defined at sys/cdef.h + */ +#if __GNUC__ +# define __decl_noreturn +# ifndef __noreturn +# define __noreturn __attribute__((noreturn)) +# endif +#else +# if defined(__WIN32__) && defined(_MSC_VER) +# define __noreturn +# define __decl_noreturn __declspec(noreturn) +# else +# define __noreturn +# define __decl_noreturn +# endif +#endif + #include <erl_nif.h> #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_PATH diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c index ce879dbfb3..61ea615de8 100644 --- a/erts/emulator/nifs/common/socket_util.c +++ b/erts/emulator/nifs/common/socket_util.c @@ -1827,7 +1827,8 @@ size_t esock_strnlen(const char *s, size_t maxlen) * */ extern -void esock_abort(const char* expr, +void __noreturn +esock_abort(const char* expr, const char* func, const char* file, int line) diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h index 3a0a84a8d8..8d35d3c06d 100644 --- a/erts/emulator/nifs/common/socket_util.h +++ b/erts/emulator/nifs/common/socket_util.h @@ -222,10 +222,11 @@ ERL_NIF_TERM esock_encode_level(ErlNifEnv* env, int level); extern size_t esock_strnlen(const char *s, size_t maxlen); extern -void esock_abort(const char* expr, - const char* func, - const char* file, - int line); +void __noreturn +esock_abort(const char* expr, + const char* func, + const char* file, + int line); extern ERL_NIF_TERM esock_self(ErlNifEnv* env); diff --git a/lib/crypto/c_src/crypto_callback.c b/lib/crypto/c_src/crypto_callback.c index 0244952a65..53b4bbf1e0 100644 --- a/lib/crypto/c_src/crypto_callback.c +++ b/lib/crypto/c_src/crypto_callback.c @@ -106,9 +106,8 @@ static void crypto_free(void* ptr CCB_FILE_LINE_ARGS) #ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */ -#if OPENSSL_VERSION_NUMBER < 0x10100000 +#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */ -#endif #include <openssl/crypto.h> @@ -132,8 +131,6 @@ static INLINE void locking(int mode, ErlNifRWLock* lock) } } -#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) - /* TODO: there should be an enif_atomic32_add_return() */ typedef int (*add_lock_function_t)(int *var, int incr, int type, const char *file, int line); @@ -192,21 +189,18 @@ DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks) &crypto_realloc, &crypto_free, -#if OPENSSL_VERSION_NUMBER < 0x10100000 -#ifdef OPENSSL_THREADS +#if defined OPENSSL_THREADS && OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) NULL, /* add_lock_function, filled in below */ &locking_function, &id_function, &dyn_create_function, &dyn_lock_function, &dyn_destroy_function -#endif /* OPENSSL_THREADS */ -#endif +#endif /* OPENSSL_THREADS && PACKED_OPENSSL_VERSION_PLAIN(1,1,0) */ }; if (!is_initialized) { -#if OPENSSL_VERSION_NUMBER < 0x10100000 -#ifdef OPENSSL_THREADS +#if defined OPENSSL_THREADS && OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) the_struct.add_lock_function = get_add_lock_function(); if (nlocks > 0) { int i; @@ -223,18 +217,15 @@ DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks) goto err; } } -#endif -#endif +#endif /* OPENSSL_THREADS && PACKED_OPENSSL_VERSION_PLAIN(1,1,0) */ is_initialized = 1; } return &the_struct; -#if OPENSSL_VERSION_NUMBER < 0x10100000 -#ifdef OPENSSL_THREADS +#if defined OPENSSL_THREADS && OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) err: return NULL; #endif -#endif } #ifdef HAVE_DYNAMIC_CRYPTO_LIB diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c index ee5dc9cd0a..a6ea54150a 100644 --- a/lib/odbc/c_src/odbcserver.c +++ b/lib/odbc/c_src/odbcserver.c @@ -178,7 +178,7 @@ static void encode_column_dyn(db_column column, int column_nr, db_state *state); static void encode_data_type(SQLSMALLINT sql_type, SQLINTEGER size, SQLSMALLINT decimal_digits, db_state *state); -static Boolean decode_params(db_state *state, byte *buffer, int *index, param_array **params, +static Boolean decode_params(db_state *state, char *buffer, int *index, param_array **params, int i, int j, int num_param_values); /*------------- Erlang port communication functions ----------------------*/ @@ -222,7 +222,7 @@ static SQLLEN* alloc_strlen_indptr(int n, int val); static void init_driver(int erl_auto_commit_mode, int erl_trace_driver, db_state *state); -static void init_param_column(param_array *params, byte *buffer, int *index, +static void init_param_column(param_array *params, char *buffer, int *index, int num_param_values, db_state* state); static void init_param_statement(int cols, @@ -235,7 +235,7 @@ static void map_dec_num_2_c_column(col_type *type, int precision, static db_result_msg map_sql_2_c_column(db_column* column, db_state *state); -static param_array * bind_parameter_arrays(byte *buffer, int *index, +static param_array * bind_parameter_arrays(char *buffer, int *index, int cols, int num_param_values, db_state *state); @@ -278,7 +278,7 @@ int main(void) msg = receive_erlang_port_msg(); - temp = strtok(msg, ";"); + temp = strtok((char*)msg, ";"); if (temp == NULL) DO_EXIT(EXIT_STDIN_BODY); length = strlen(temp); @@ -509,7 +509,9 @@ static db_result_msg db_connect(byte *args, db_state *state) diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state)); strcat((char *)diagnos.error_msg, " Connection to database failed."); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError ); + msg = encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError ); if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC, connection_handle(state)))) @@ -544,7 +546,9 @@ static db_result_msg db_connect(byte *args, db_state *state) diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state)); strcat((char *)diagnos.error_msg, " Set autocommit mode failed."); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char*)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC, connection_handle(state)))) @@ -576,7 +580,9 @@ static db_result_msg db_close_connection(db_state *state) if (!sql_success(result)) { diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state)); - return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + return encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); } if(!sql_success(SQLFreeHandle(SQL_HANDLE_DBC, @@ -603,7 +609,9 @@ static db_result_msg db_end_tran(byte compleationtype, db_state *state) if (!sql_success(result)) { diagnos = get_diagnos(SQL_HANDLE_DBC, connection_handle(state), extended_errors(state)); - return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + return encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); } else { return encode_atom_message("ok"); } @@ -645,7 +653,7 @@ static db_result_msg db_query(byte *sql, db_state *state) it as we want a nice and clean Erlang API */ if((strcmp((char *)is_error, "error") == 0)) { - msg = encode_error_message((char *)diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char *)diagnos.error_msg,extended_error(state, diagnos.sqlState), diagnos.nativeError); clean_state(state); return msg; } @@ -686,7 +694,7 @@ static db_result_msg db_query(byte *sql, db_state *state) ei_x_free(&(dynamic_buffer(state))); return msg; } else { - msg.buffer = dynamic_buffer(state).buff; + msg.buffer = (byte*)dynamic_buffer(state).buff; msg.length = dynamic_buffer(state).index; msg.dyn_alloc = TRUE; return msg; @@ -722,7 +730,9 @@ static db_result_msg db_select_count(byte *sql, db_state *state) if(!sql_success(SQLExecDirect(statement_handle(state), (SQLCHAR *)sql, SQL_NTS))) { diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); clean_state(state); - return encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + return encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); } if(!sql_success(SQLNumResultCols(statement_handle(state), @@ -810,7 +820,7 @@ static db_result_msg db_select(byte *args, db_state *state) ei_x_free(&(dynamic_buffer(state))); return msg; } else { - msg.buffer = dynamic_buffer(state).buff; + msg.buffer = (byte*)dynamic_buffer(state).buff; msg.length = dynamic_buffer(state).index; msg.dyn_alloc = TRUE; return msg; @@ -819,9 +829,10 @@ static db_result_msg db_select(byte *args, db_state *state) /* Description: Handles parameterized queries ex: INSERT INTO FOO VALUES(?, ?) */ -static db_result_msg db_param_query(byte *buffer, db_state *state) +static db_result_msg db_param_query(byte *byte_buffer, db_state *state) { - byte *sql; + char *sql; + char *buffer = (char *)byte_buffer; db_result_msg msg; SQLLEN num_param_values; int i, ver = 0, @@ -847,7 +858,7 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) ei_get_type(buffer, &index, &erl_type, &size); - sql = (byte*)safe_malloc((sizeof(byte) * (size + 1))); + sql = safe_malloc((sizeof(byte) * (size + 1))); ei_decode_string(buffer, &index, sql); ei_decode_long(buffer, &index, &long_num_param_values); @@ -871,7 +882,9 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) updates/deletes that affect no rows */ if(!sql_success(result) && !(result == SQL_NO_DATA && !strcmp((char *)diagnos.sqlState, INFO))) { - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char*)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); } else { for (i = 0; i < param_status.params_processed; i++) { switch (param_status.param_status_array[i]) { @@ -886,7 +899,9 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) default: diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char*)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); i = param_status.params_processed; break; } @@ -899,7 +914,7 @@ static db_result_msg db_param_query(byte *buffer, db_state *state) msg = encode_result(state); } if(msg.length == 0) { - msg.buffer = dynamic_buffer(state).buff; + msg.buffer = (byte *)dynamic_buffer(state).buff; msg.length = dynamic_buffer(state).index; msg.dyn_alloc = TRUE; } else { /* Error occurred */ @@ -956,7 +971,9 @@ static db_result_msg db_describe_table(byte *sql, db_state *state) if (!sql_success(SQLPrepare(statement_handle(state), (SQLCHAR *)sql, SQL_NTS))){ diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); clean_state(state); return msg; } @@ -964,7 +981,9 @@ static db_result_msg db_describe_table(byte *sql, db_state *state) if(!sql_success(SQLNumResultCols(statement_handle(state), &num_of_columns))) { diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); clean_state(state); return msg; } @@ -992,7 +1011,7 @@ static db_result_msg db_describe_table(byte *sql, db_state *state) ei_x_encode_empty_list(&dynamic_buffer(state)); clean_state(state); - msg.buffer = dynamic_buffer(state).buff; + msg.buffer = (byte *)dynamic_buffer(state).buff; msg.length = dynamic_buffer(state).index; msg.dyn_alloc = TRUE; return msg; @@ -1088,7 +1107,9 @@ static db_result_msg encode_result(db_state *state) if(!sql_success(SQLNumResultCols(statement_handle(state), &num_of_columns))) { diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); clean_state(state); return msg; } @@ -1105,7 +1126,9 @@ static db_result_msg encode_result(db_state *state) if(!sql_success(SQLRowCount(statement_handle(state), &RowCountPtr))) { diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char *)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); clean_state(state); return msg; } @@ -1652,7 +1675,7 @@ static void encode_data_type(SQLSMALLINT sql_type, SQLINTEGER size, } } -static Boolean decode_params(db_state *state, byte *buffer, int *index, param_array **params, +static Boolean decode_params(db_state *state, char *buffer, int *index, param_array **params, int i, int j, int num_param_values) { int erl_type, size; @@ -1688,7 +1711,7 @@ static Boolean decode_params(db_state *state, byte *buffer, int *index, param_ar if(erl_type != ERL_STRING_EXT) { return FALSE; } - ei_decode_string(buffer, index, &(param->values.string[param->offset])); + ei_decode_string(buffer, index, (char*)&(param->values.string[param->offset])); param->offset += param->type.len; } break; @@ -2197,7 +2220,7 @@ static void init_driver(int erl_auto_commit_mode, int erl_trace_driver, DO_EXIT(EXIT_CONNECTION); } -static void init_param_column(param_array *params, byte *buffer, int *index, +static void init_param_column(param_array *params, char *buffer, int *index, int num_param_values, db_state* state) { long user_type, precision, scale, length; @@ -2509,7 +2532,7 @@ static db_result_msg map_sql_2_c_column(db_column* column, db_state *state) return msg; } -static param_array * bind_parameter_arrays(byte *buffer, int *index, +static param_array * bind_parameter_arrays(char *buffer, int *index, int cols, int num_param_values, db_state *state) { @@ -2669,7 +2692,7 @@ static db_result_msg retrive_scrollable_cursor_support_info(db_state *state) ei_x_encode_atom(&dynamic_buffer(state), "false"); ei_x_encode_atom(&dynamic_buffer(state), "false"); } - msg.buffer = dynamic_buffer(state).buff; + msg.buffer = (byte *)dynamic_buffer(state).buff; msg.length = dynamic_buffer(state).index; msg.dyn_alloc = TRUE; return msg; @@ -2700,7 +2723,9 @@ static db_result_msg more_result_sets(db_state *state) diagnos = get_diagnos(SQL_HANDLE_STMT, statement_handle(state), extended_errors(state)); strcat((char *)diagnos.error_msg, "Failed to create on of the result sets"); - msg = encode_error_message(diagnos.error_msg, extended_error(state, diagnos.sqlState), diagnos.nativeError); + msg = encode_error_message((char*)diagnos.error_msg, + extended_error(state, diagnos.sqlState), + diagnos.nativeError); return msg; } } diff --git a/lib/wx/configure.in b/lib/wx/configure.in index 57212302ae..4b6e95b9e9 100644 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -587,8 +587,6 @@ AC_CHECK_TYPES([GLintptr, GLintptrARB, GLchar, # include <OpenGL/gl.h> #endif ]) - -dnl AC_MSG_CHECKING(GLU Callbacks uses Tiger Style) AC_LANG_PUSH(C++) @@ -610,7 +608,7 @@ AC_TRY_COMPILE([ void CALLBACK foo() {}; ], [ - GLUtesselator* tess; + GLUtesselator* tess; gluTessCallback(tess,GLU_TESS_VERTEX,(GLvoid (*)(...)) foo); ], [TESS_CB_TIGER_STYLE=yes @@ -660,7 +658,7 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([ // it isn't in too old wxWidgets versions wxString test = wxString::FromUTF8((const char *)"foo"); wxStyledTextCtrl * foo = new wxStyledTextCtrl(); - return true; + return foo; }; }; IMPLEMENT_APP(MyApp) |