diff mbox

[U-Boot,4/7] Check if compiler-provided <stdint.h> and <inttypes.h> are available if CONFIG_USE_STDINT=y (MAD)

Message ID 1419243363-11542-5-git-send-email-yamada.m@jp.panasonic.com
State RFC
Delegated to: Tom Rini
Headers show

Commit Message

Masahiro Yamada Dec. 22, 2014, 10:16 a.m. UTC
CONFIG_USE_STDINT was introduced to use compiler-provided types for
fixed-width variables.
This must be consistent everywhere to avoid warnings/errors
including printf() and friends.

Assume the code below

  uint32_t foo;

  printf("foo= %x\n", foo);

If <stdint.h> is included, uint32_t is defined by the compiler.
The code above only works on compilers that define "uint32_t"
as "unsigned int".  Actually there exist compilers that define
"uint32_t" as "unsigned long".

Going forward, to print out fixed-width variables, we always have
to use PRIxN like this

  uint32_t foo;

  printf("foo= " PRIx32 "\n", foo);

Notice,

  - Typedefs ( uint32_t, int32_t etc.) are provided by <stdint.h>
  - Printf formats ( PRIx32, PRId32 etc.) are provided by <inttypes.h>

Also notice, it makes sense only when <stdint.h> and <inttypes.h> are provided by
the same compiler.
^^^^^^^^^^^^^^^^^^

Commit 4166ecb24 (Add some standard headers external code might need) added
hard-coded include/inttypes.h.
It provides hard-coded PRIx32 "x", but it does not make sense.
Some compiler's <stdint.h> define "uint32_t" as "unsigned long"
and expect the format string "lx" to print out "uint32_t" variable.

This commit:
  - Adds scripts/gcc-have-stdint.sh to check if the compiler is
    providing both <stdint.h> and <inttypes.h>

  - Modifies config.mk to error-out if CONFIG_USE_STDINT is enabled,
    but <stdint.h> or <inttyps.h> is missing

  - Modifies the top Makefile to delete "-nostdinc" option and allow to
    include compiler-provided <inttypes.h>

  - Remove hard-coded include/inttypes.h

Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
Cc: Gabe Black <gabeblack@chromium.org>
Cc: Simon Glass <sjg@chromium.org>
Cc: Bill Richardson <wfrichar@google.com>
Cc: Tom Rini <trini@ti.com>
---

 Makefile                   |   2 +-
 config.mk                  |  12 ++
 include/inttypes.h         | 287 ---------------------------------------------
 scripts/gcc-have-stdint.sh |  21 ++++
 4 files changed, 34 insertions(+), 288 deletions(-)
 delete mode 100644 include/inttypes.h
 create mode 100755 scripts/gcc-have-stdint.sh

Comments

Simon Glass Dec. 23, 2014, 4:46 a.m. UTC | #1
Hi Masahiro,

On 22 December 2014 at 03:16, Masahiro Yamada <yamada.m@jp.panasonic.com> wrote:
> CONFIG_USE_STDINT was introduced to use compiler-provided types for
> fixed-width variables.
> This must be consistent everywhere to avoid warnings/errors
> including printf() and friends.
>
> Assume the code below
>
>   uint32_t foo;
>
>   printf("foo= %x\n", foo);
>
> If <stdint.h> is included, uint32_t is defined by the compiler.
> The code above only works on compilers that define "uint32_t"
> as "unsigned int".  Actually there exist compilers that define
> "uint32_t" as "unsigned long".
>
> Going forward, to print out fixed-width variables, we always have
> to use PRIxN like this
>
>   uint32_t foo;
>
>   printf("foo= " PRIx32 "\n", foo);
>
> Notice,
>
>   - Typedefs ( uint32_t, int32_t etc.) are provided by <stdint.h>
>   - Printf formats ( PRIx32, PRId32 etc.) are provided by <inttypes.h>
>
> Also notice, it makes sense only when <stdint.h> and <inttypes.h> are provided by
> the same compiler.
> ^^^^^^^^^^^^^^^^^^
>
> Commit 4166ecb24 (Add some standard headers external code might need) added
> hard-coded include/inttypes.h.
> It provides hard-coded PRIx32 "x", but it does not make sense.
> Some compiler's <stdint.h> define "uint32_t" as "unsigned long"
> and expect the format string "lx" to print out "uint32_t" variable.
>
> This commit:
>   - Adds scripts/gcc-have-stdint.sh to check if the compiler is
>     providing both <stdint.h> and <inttypes.h>
>
>   - Modifies config.mk to error-out if CONFIG_USE_STDINT is enabled,
>     but <stdint.h> or <inttyps.h> is missing
>
>   - Modifies the top Makefile to delete "-nostdinc" option and allow to
>     include compiler-provided <inttypes.h>
>
>   - Remove hard-coded include/inttypes.h

This patch looks good to me except that I don't understand why you are
removing inttypes.h? Where will the PRI defines come from? Or is it
because you are fixing things such that the defines are not needed
anymore?

>
> Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
> Cc: Gabe Black <gabeblack@chromium.org>
> Cc: Simon Glass <sjg@chromium.org>
> Cc: Bill Richardson <wfrichar@google.com>
> Cc: Tom Rini <trini@ti.com>
> ---
>
>  Makefile                   |   2 +-
>  config.mk                  |  12 ++
>  include/inttypes.h         | 287 ---------------------------------------------
>  scripts/gcc-have-stdint.sh |  21 ++++
>  4 files changed, 34 insertions(+), 288 deletions(-)
>  delete mode 100644 include/inttypes.h
>  create mode 100755 scripts/gcc-have-stdint.sh
>

[snip]

Regards,
Simon
Masahiro Yamada Dec. 24, 2014, 8:44 a.m. UTC | #2
Hi Simon,


On Mon, 22 Dec 2014 21:46:26 -0700
Simon Glass <sjg@chromium.org> wrote:

> Hi Masahiro,
> 
> On 22 December 2014 at 03:16, Masahiro Yamada <yamada.m@jp.panasonic.com> wrote:
> > CONFIG_USE_STDINT was introduced to use compiler-provided types for
> > fixed-width variables.
> > This must be consistent everywhere to avoid warnings/errors
> > including printf() and friends.
> >
> > Assume the code below
> >
> >   uint32_t foo;
> >
> >   printf("foo= %x\n", foo);
> >
> > If <stdint.h> is included, uint32_t is defined by the compiler.
> > The code above only works on compilers that define "uint32_t"
> > as "unsigned int".  Actually there exist compilers that define
> > "uint32_t" as "unsigned long".
> >
> > Going forward, to print out fixed-width variables, we always have
> > to use PRIxN like this
> >
> >   uint32_t foo;
> >
> >   printf("foo= " PRIx32 "\n", foo);
> >
> > Notice,
> >
> >   - Typedefs ( uint32_t, int32_t etc.) are provided by <stdint.h>
> >   - Printf formats ( PRIx32, PRId32 etc.) are provided by <inttypes.h>
> >
> > Also notice, it makes sense only when <stdint.h> and <inttypes.h> are provided by
> > the same compiler.
> > ^^^^^^^^^^^^^^^^^^
> >
> > Commit 4166ecb24 (Add some standard headers external code might need) added
> > hard-coded include/inttypes.h.
> > It provides hard-coded PRIx32 "x", but it does not make sense.
> > Some compiler's <stdint.h> define "uint32_t" as "unsigned long"
> > and expect the format string "lx" to print out "uint32_t" variable.
> >
> > This commit:
> >   - Adds scripts/gcc-have-stdint.sh to check if the compiler is
> >     providing both <stdint.h> and <inttypes.h>
> >
> >   - Modifies config.mk to error-out if CONFIG_USE_STDINT is enabled,
> >     but <stdint.h> or <inttyps.h> is missing
> >
> >   - Modifies the top Makefile to delete "-nostdinc" option and allow to
> >     include compiler-provided <inttypes.h>
> >
> >   - Remove hard-coded include/inttypes.h
> 
> This patch looks good to me except that I don't understand why you are
> removing inttypes.h? Where will the PRI defines come from? Or is it
> because you are fixing things such that the defines are not needed
> anymore?

According to this question, I am afraid you are not understanding <inttypes.h> very well.
Maybe is this page useful?
http://pubs.opengroup.org/onlinepubs/009695399/basedefs/inttypes.h.html


My commit description has also answered your question:

Notice,
   - Typedefs ( uint32_t, int32_t etc.) are provided by <stdint.h>
   - Printf formats ( PRIx32, PRId32 etc.) are provided by <inttypes.h>
Also notice, it makes sense only when <stdint.h> and <inttypes.h> are provided by
the same compiler.


Best Regards
Masahiro Yamada
diff mbox

Patch

diff --git a/Makefile b/Makefile
index 1560bff..b44e504 100644
--- a/Makefile
+++ b/Makefile
@@ -591,7 +591,7 @@  UBOOTINCLUDE    := \
 		-I$(srctree)/arch/$(ARCH)/include \
 		-include $(srctree)/include/linux/kconfig.h
 
-NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+NOSTDINC_FLAGS += -isystem $(shell $(CC) -print-file-name=include)
 CHECKFLAGS     += $(NOSTDINC_FLAGS)
 
 # FIX ME
diff --git a/config.mk b/config.mk
index 64c2951..91f60d4 100644
--- a/config.mk
+++ b/config.mk
@@ -64,6 +64,18 @@  ifneq ($(USE_STDINT),)
 PLATFORM_CPPFLAGS += -DCONFIG_USE_STDINT
 endif
 
+ifeq ($(CONFIG_USE_STDINT),y)
+HAVE_STDINT := $(shell $(CONFIG_SHELL) scripts/gcc-have-stdint.sh $(CC))
+
+ifeq ($(HAVE_STDINT),)
+$(warning you have enabled CONFIG_USE_STDINT (or given USE_STDINT=1 from the command line))
+$(warning but your compiler is not providing <stdint.h> or <inttypes.h>.)
+$(error check your compiler.)
+
+endif
+
+endif
+
 #########################################################################
 
 RELFLAGS := $(PLATFORM_RELFLAGS)
diff --git a/include/inttypes.h b/include/inttypes.h
deleted file mode 100644
index e2e569d..0000000
--- a/include/inttypes.h
+++ /dev/null
@@ -1,287 +0,0 @@ 
-/*
- * Copyright (C) 1997-2001, 2004, 2007 Free Software Foundation, Inc.
- *
- * This file is taken from the GNU C Library v2.15, with the unimplemented
- * functions removed and a few style fixes.
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-/*
- *	ISO C99: 7.8 Format conversion of integer types	<inttypes.h>
- */
-
-#ifndef _INTTYPES_H
-#define _INTTYPES_H	1
-
-#include <linux/compiler.h>
-
-/* Get a definition for wchar_t.  But we must not define wchar_t itself.  */
-#ifndef ____gwchar_t_defined
-# ifdef __cplusplus
-#  define __gwchar_t wchar_t
-# elif defined __WCHAR_TYPE__
-typedef __WCHAR_TYPE__ __gwchar_t;
-# else
-#  define __need_wchar_t
-#  include <stddef.h>
-typedef wchar_t __gwchar_t;
-# endif
-# define ____gwchar_t_defined	1
-#endif
-
-
-/* The ISO C99 standard specifies that these macros must only be
-   defined if explicitly requested.  */
-#if !defined __cplusplus || defined __STDC_FORMAT_MACROS
-
-#ifdef CONFIG_USE_STDINT
-# if __WORDSIZE == 64
-#  define __PRI64_PREFIX	"l"
-#  define __PRIPTR_PREFIX	"l"
-# else
-#  define __PRI64_PREFIX	"ll"
-#  define __PRIPTR_PREFIX
-# endif
-#else
-/* linux/types.h always uses long long for 64-bit and long for uintptr_t */
-# define __PRI64_PREFIX	"ll"
-# define __PRIPTR_PREFIX	"l"
-#endif
-
-/* Macros for printing format specifiers.  */
-
-/* Decimal notation.  */
-# define PRId8		"d"
-# define PRId16		"d"
-# define PRId32		"d"
-# define PRId64		__PRI64_PREFIX "d"
-
-# define PRIdLEAST8	"d"
-# define PRIdLEAST16	"d"
-# define PRIdLEAST32	"d"
-# define PRIdLEAST64	__PRI64_PREFIX "d"
-
-# define PRIdFAST8	"d"
-# define PRIdFAST16	__PRIPTR_PREFIX "d"
-# define PRIdFAST32	__PRIPTR_PREFIX "d"
-# define PRIdFAST64	__PRI64_PREFIX "d"
-
-
-# define PRIi8		"i"
-# define PRIi16		"i"
-# define PRIi32		"i"
-# define PRIi64		__PRI64_PREFIX "i"
-
-# define PRIiLEAST8	"i"
-# define PRIiLEAST16	"i"
-# define PRIiLEAST32	"i"
-# define PRIiLEAST64	__PRI64_PREFIX "i"
-
-# define PRIiFAST8	"i"
-# define PRIiFAST16	__PRIPTR_PREFIX "i"
-# define PRIiFAST32	__PRIPTR_PREFIX "i"
-# define PRIiFAST64	__PRI64_PREFIX "i"
-
-/* Octal notation.  */
-# define PRIo8		"o"
-# define PRIo16		"o"
-# define PRIo32		"o"
-# define PRIo64		__PRI64_PREFIX "o"
-
-# define PRIoLEAST8	"o"
-# define PRIoLEAST16	"o"
-# define PRIoLEAST32	"o"
-# define PRIoLEAST64	__PRI64_PREFIX "o"
-
-# define PRIoFAST8	"o"
-# define PRIoFAST16	__PRIPTR_PREFIX "o"
-# define PRIoFAST32	__PRIPTR_PREFIX "o"
-# define PRIoFAST64	__PRI64_PREFIX "o"
-
-/* Unsigned integers.  */
-# define PRIu8		"u"
-# define PRIu16		"u"
-# define PRIu32		"u"
-# define PRIu64		__PRI64_PREFIX "u"
-
-# define PRIuLEAST8	"u"
-# define PRIuLEAST16	"u"
-# define PRIuLEAST32	"u"
-# define PRIuLEAST64	__PRI64_PREFIX "u"
-
-# define PRIuFAST8	"u"
-# define PRIuFAST16	__PRIPTR_PREFIX "u"
-# define PRIuFAST32	__PRIPTR_PREFIX "u"
-# define PRIuFAST64	__PRI64_PREFIX "u"
-
-/* lowercase hexadecimal notation.  */
-# define PRIx8		"x"
-# define PRIx16		"x"
-# define PRIx32		"x"
-# define PRIx64		__PRI64_PREFIX "x"
-
-# define PRIxLEAST8	"x"
-# define PRIxLEAST16	"x"
-# define PRIxLEAST32	"x"
-# define PRIxLEAST64	__PRI64_PREFIX "x"
-
-# define PRIxFAST8	"x"
-# define PRIxFAST16	__PRIPTR_PREFIX "x"
-# define PRIxFAST32	__PRIPTR_PREFIX "x"
-# define PRIxFAST64	__PRI64_PREFIX "x"
-
-/* UPPERCASE hexadecimal notation.  */
-# define PRIX8		"X"
-# define PRIX16		"X"
-# define PRIX32		"X"
-# define PRIX64		__PRI64_PREFIX "X"
-
-# define PRIXLEAST8	"X"
-# define PRIXLEAST16	"X"
-# define PRIXLEAST32	"X"
-# define PRIXLEAST64	__PRI64_PREFIX "X"
-
-# define PRIXFAST8	"X"
-# define PRIXFAST16	__PRIPTR_PREFIX "X"
-# define PRIXFAST32	__PRIPTR_PREFIX "X"
-# define PRIXFAST64	__PRI64_PREFIX "X"
-
-
-/* Macros for printing `intmax_t' and `uintmax_t'.  */
-# define PRIdMAX	__PRI64_PREFIX "d"
-# define PRIiMAX	__PRI64_PREFIX "i"
-# define PRIoMAX	__PRI64_PREFIX "o"
-# define PRIuMAX	__PRI64_PREFIX "u"
-# define PRIxMAX	__PRI64_PREFIX "x"
-# define PRIXMAX	__PRI64_PREFIX "X"
-
-
-/* Macros for printing `intptr_t' and `uintptr_t'.  */
-# define PRIdPTR	__PRIPTR_PREFIX "d"
-# define PRIiPTR	__PRIPTR_PREFIX "i"
-# define PRIoPTR	__PRIPTR_PREFIX "o"
-# define PRIuPTR	__PRIPTR_PREFIX "u"
-# define PRIxPTR	__PRIPTR_PREFIX "x"
-# define PRIXPTR	__PRIPTR_PREFIX "X"
-
-
-/* Macros for scanning format specifiers.  */
-
-/* Signed decimal notation.  */
-# define SCNd8		"hhd"
-# define SCNd16		"hd"
-# define SCNd32		"d"
-# define SCNd64		__PRI64_PREFIX "d"
-
-# define SCNdLEAST8	"hhd"
-# define SCNdLEAST16	"hd"
-# define SCNdLEAST32	"d"
-# define SCNdLEAST64	__PRI64_PREFIX "d"
-
-# define SCNdFAST8	"hhd"
-# define SCNdFAST16	__PRIPTR_PREFIX "d"
-# define SCNdFAST32	__PRIPTR_PREFIX "d"
-# define SCNdFAST64	__PRI64_PREFIX "d"
-
-/* Signed decimal notation.  */
-# define SCNi8		"hhi"
-# define SCNi16		"hi"
-# define SCNi32		"i"
-# define SCNi64		__PRI64_PREFIX "i"
-
-# define SCNiLEAST8	"hhi"
-# define SCNiLEAST16	"hi"
-# define SCNiLEAST32	"i"
-# define SCNiLEAST64	__PRI64_PREFIX "i"
-
-# define SCNiFAST8	"hhi"
-# define SCNiFAST16	__PRIPTR_PREFIX "i"
-# define SCNiFAST32	__PRIPTR_PREFIX "i"
-# define SCNiFAST64	__PRI64_PREFIX "i"
-
-/* Unsigned decimal notation.  */
-# define SCNu8		"hhu"
-# define SCNu16		"hu"
-# define SCNu32		"u"
-# define SCNu64		__PRI64_PREFIX "u"
-
-# define SCNuLEAST8	"hhu"
-# define SCNuLEAST16	"hu"
-# define SCNuLEAST32	"u"
-# define SCNuLEAST64	__PRI64_PREFIX "u"
-
-# define SCNuFAST8	"hhu"
-# define SCNuFAST16	__PRIPTR_PREFIX "u"
-# define SCNuFAST32	__PRIPTR_PREFIX "u"
-# define SCNuFAST64	__PRI64_PREFIX "u"
-
-/* Octal notation.  */
-# define SCNo8		"hho"
-# define SCNo16		"ho"
-# define SCNo32		"o"
-# define SCNo64		__PRI64_PREFIX "o"
-
-# define SCNoLEAST8	"hho"
-# define SCNoLEAST16	"ho"
-# define SCNoLEAST32	"o"
-# define SCNoLEAST64	__PRI64_PREFIX "o"
-
-# define SCNoFAST8	"hho"
-# define SCNoFAST16	__PRIPTR_PREFIX "o"
-# define SCNoFAST32	__PRIPTR_PREFIX "o"
-# define SCNoFAST64	__PRI64_PREFIX "o"
-
-/* Hexadecimal notation.  */
-# define SCNx8		"hhx"
-# define SCNx16		"hx"
-# define SCNx32		"x"
-# define SCNx64		__PRI64_PREFIX "x"
-
-# define SCNxLEAST8	"hhx"
-# define SCNxLEAST16	"hx"
-# define SCNxLEAST32	"x"
-# define SCNxLEAST64	__PRI64_PREFIX "x"
-
-# define SCNxFAST8	"hhx"
-# define SCNxFAST16	__PRIPTR_PREFIX "x"
-# define SCNxFAST32	__PRIPTR_PREFIX "x"
-# define SCNxFAST64	__PRI64_PREFIX "x"
-
-
-/* Macros for scanning `intmax_t' and `uintmax_t'.  */
-# define SCNdMAX	__PRI64_PREFIX "d"
-# define SCNiMAX	__PRI64_PREFIX "i"
-# define SCNoMAX	__PRI64_PREFIX "o"
-# define SCNuMAX	__PRI64_PREFIX "u"
-# define SCNxMAX	__PRI64_PREFIX "x"
-
-/* Macros for scaning `intptr_t' and `uintptr_t'.  */
-# define SCNdPTR	__PRIPTR_PREFIX "d"
-# define SCNiPTR	__PRIPTR_PREFIX "i"
-# define SCNoPTR	__PRIPTR_PREFIX "o"
-# define SCNuPTR	__PRIPTR_PREFIX "u"
-# define SCNxPTR	__PRIPTR_PREFIX "x"
-
-#endif	/* C++ && format macros */
-
-
-#if __WORDSIZE == 64
-
-/* We have to define the `uintmax_t' type using `ldiv_t'.  */
-typedef struct {
-	long int quot;		/* Quotient.  */
-	long int rem;		/* Remainder.  */
-} imaxdiv_t;
-
-#else
-
-/* We have to define the `uintmax_t' type using `lldiv_t'.  */
-typedef struct {
-	long long int quot;		/* Quotient.  */
-	long long int rem;		/* Remainder.  */
-} imaxdiv_t;
-
-#endif
-
-#endif /* inttypes.h */
diff --git a/scripts/gcc-have-stdint.sh b/scripts/gcc-have-stdint.sh
new file mode 100755
index 0000000..555ede6
--- /dev/null
+++ b/scripts/gcc-have-stdint.sh
@@ -0,0 +1,21 @@ 
+#!/bin/sh
+#
+# Test if the compiler has <stdint.h> and <inttypes.>
+# Kernel.org toolchains do not provide them.
+#
+# CONFIG_USE_STDINT makes sense only when
+# both <stdint.h> and <inttypes.h> are provided by the compiler.
+#
+TMP="$$"
+
+cat <<END | $@ -Werror -x c - -c -o $TMP >/dev/null 2>&1 && echo "y"
+#include <stdint.h>
+#include <inttypes.h>
+
+int main(void)
+{
+	return 0;
+}
+END
+
+rm -f $TMP