Project

General

Profile

Actions

Bug #18156

closed

3.0.2 configuration checks by default for C++ compiler instead of C?

Added by vo.x (Vit Ondruch) over 3 years ago. Updated about 2 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]
[ruby-core:105180]

Description

It seems that with git|c32375883a696fcf8e9e99875f1339ee5474a255 the configure script does not check for C compiler but for C++ using Autoconf 2.71. This is the difference between 2.69 1 and 2.71 2:

--- 2.69
+++ 2.71
@@ -1,40 +1,27 @@
-+ ./configure --prefix=/home/chkbuild/chkbuild/tmp/build/20210908T123006Z --with-baseruby=/home/chkbuild/.rbenv/versions/3.0.2/bin/ruby --enable-debug-env --with-valgrind
-downloading config.guess ... done
-downloading config.sub ... done
++ ./configure --prefix=/home/chkbuild/chkbuild/tmp/build/20210908T120006Z --with-baseruby=/home/chkbuild/.rbenv/versions/3.0.2/bin/ruby --enable-debug-env --with-valgrind
+tool/config.guess already exists
+tool/config.sub already exists
 checking build system type... x86_64-pc-linux-gnu
 checking host system type... x86_64-pc-linux-gnu
 checking target system type... x86_64-pc-linux-gnu
 checking for gcc... gcc
 checking for ld... ld
 checking for gcc-ar... gcc-ar
-checking for g++... no
+checking for g++... g++
 checking for gcc-nm... gcc-nm
 checking for gcc-ranlib... gcc-ranlib
-checking for gcc... (cached) gcc
-checking whether the C compiler works... yes
-checking for C compiler default output file name... a.out
+checking whether the C++ compiler works... yes
+checking for C++ compiler default output file name... a.out
 checking for suffix of executables... 
 checking whether we are cross compiling... no
 checking for suffix of object files... o
-checking whether we are using the GNU C compiler... yes
+checking whether the compiler supports GNU C++... yes
+checking whether g++ accepts -g... yes
+checking for g++ option to enable C++11 features... none needed
+checking for gcc... (cached) gcc
+checking whether the compiler supports GNU C... yes
 checking whether gcc accepts -g... yes
-checking for gcc option to accept ISO C89... none needed
-checking for gcc option to accept ISO C99... none needed
-checking for g++... no
-checking for c++... no
-checking for gpp... no
-checking for aCC... no
-checking for CC... no
-checking for cxx... no
-checking for cc++... no
-checking for cl.exe... no
-checking for FCC... no
-checking for KCC... no
-checking for RCC... no
-checking for xlC_r... no
-checking for xlC... no
-checking whether we are using the GNU C++ compiler... no
-checking whether g++ accepts -g... no
+checking for gcc option to enable C11 features... none needed
 checking how to run the C preprocessor... gcc -E
 checking for ranlib... (cached) gcc-ranlib
 checking for gas... no
@@ -45,22 +32,20 @@
 checking for objdump... objdump
 checking for gstrip... no
 checking for strip... strip
-checking for grep that handles long lines and -e... /usr/bin/grep
-checking for egrep... /usr/bin/grep -E
-checking for ANSI C header files... yes
-checking for sys/types.h... yes
-checking for sys/stat.h... yes
+checking for stdio.h... yes
 checking for stdlib.h... yes
 checking for string.h... yes
-checking for memory.h... yes
-checking for strings.h... yes
 checking for inttypes.h... yes
 checking for stdint.h... yes
+checking for strings.h... yes
+checking for sys/stat.h... yes
+checking for sys/types.h... yes
 checking for unistd.h... yes
-checking minix/config.h usability... no
-checking minix/config.h presence... no
+checking for wchar.h... yes
 checking for minix/config.h... no
+checking for vfork.h... no
 checking whether it is safe to define __EXTENSIONS__... yes
+checking whether _XOPEN_SOURCE should be defined... no
 checking whether the linker is GNU ld... yes
 checking whether gcc -E accepts -o... yes
 checking for gcc... /usr/bin/gcc
@@ -68,7 +53,7 @@
 checking whether ln -s works... yes
 checking whether make sets $(MAKE)... yes
 checking for a BSD-compatible install... /usr/bin/install -c
-checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for a race-free mkdir -p... /usr/bin/mkdir -p
 checking for dtrace... no
 checking for dot... no
 checking for doxygen... no
@@ -126,157 +111,64 @@
 checking whether -fexcess-precision=standard is accepted as CFLAGS... yes
 checking whether -fp-model precise is accepted as CFLAGS... no
 checking whether compiler has statement and declarations in expressions... yes
-configure: Test skipped due to lack of a C++ compiler.
+checking whether CXXFLAGS is valid... yes
 checking for crypt in -lcrypt... yes
 checking for dlopen in -ldl... yes
 checking for shl_load in -ldld... no
 checking for shutdown in -lsocket... no
 checking for dirent.h that defines DIR... yes
 checking for library containing opendir... none required
+checking for _Bool... yes
 checking for stdbool.h that conforms to C99... yes
-checking for _Bool... yes
 checking for sys/wait.h that is POSIX.1 compatible... yes
-checking atomic.h usability... no
-checking atomic.h presence... no
 checking for atomic.h... no
-checking copyfile.h usability... no
-checking copyfile.h presence... no
 checking for copyfile.h... no
-checking direct.h usability... no
-checking direct.h presence... no
 checking for direct.h... no
-checking grp.h usability... yes
-checking grp.h presence... yes
 checking for grp.h... yes
-checking fcntl.h usability... yes
-checking fcntl.h presence... yes
 checking for fcntl.h... yes
-checking float.h usability... yes
-checking float.h presence... yes
 checking for float.h... yes
-checking ieeefp.h usability... no
-checking ieeefp.h presence... no
 checking for ieeefp.h... no
-checking intrinsics.h usability... no
-checking intrinsics.h presence... no
 checking for intrinsics.h... no
-checking langinfo.h usability... yes
-checking langinfo.h presence... yes
 checking for langinfo.h... yes
-checking limits.h usability... yes
-checking limits.h presence... yes
 checking for limits.h... yes
-checking locale.h usability... yes
-checking locale.h presence... yes
 checking for locale.h... yes
-checking malloc.h usability... yes
-checking malloc.h presence... yes
 checking for malloc.h... yes
-checking malloc/malloc.h usability... no
-checking malloc/malloc.h presence... no
 checking for malloc/malloc.h... no
-checking malloc_np.h usability... no
-checking malloc_np.h presence... no
 checking for malloc_np.h... no
-checking net/socket.h usability... no
-checking net/socket.h presence... no
 checking for net/socket.h... no
-checking process.h usability... no
-checking process.h presence... no
 checking for process.h... no
-checking pwd.h usability... yes
-checking pwd.h presence... yes
 checking for pwd.h... yes
-checking sanitizer/asan_interface.h usability... yes
-checking sanitizer/asan_interface.h presence... yes
 checking for sanitizer/asan_interface.h... yes
-checking sanitizer/msan_interface.h usability... no
-checking sanitizer/msan_interface.h presence... no
 checking for sanitizer/msan_interface.h... no
-checking setjmpex.h usability... no
-checking setjmpex.h presence... no
 checking for setjmpex.h... no
-checking stdalign.h usability... yes
-checking stdalign.h presence... yes
 checking for stdalign.h... yes
-checking sys/attr.h usability... no
-checking sys/attr.h presence... no
 checking for sys/attr.h... no
-checking sys/eventfd.h usability... yes
-checking sys/eventfd.h presence... yes
 checking for sys/eventfd.h... yes
-checking sys/fcntl.h usability... yes
-checking sys/fcntl.h presence... yes
 checking for sys/fcntl.h... yes
-checking sys/file.h usability... yes
-checking sys/file.h presence... yes
 checking for sys/file.h... yes
-checking sys/id.h usability... no
-checking sys/id.h presence... no
 checking for sys/id.h... no
-checking sys/ioctl.h usability... yes
-checking sys/ioctl.h presence... yes
 checking for sys/ioctl.h... yes
-checking sys/mkdev.h usability... no
-checking sys/mkdev.h presence... no
 checking for sys/mkdev.h... no
-checking sys/param.h usability... yes
-checking sys/param.h presence... yes
 checking for sys/param.h... yes
-checking sys/prctl.h usability... yes
-checking sys/prctl.h presence... yes
 checking for sys/prctl.h... yes
-checking sys/random.h usability... yes
-checking sys/random.h presence... yes
 checking for sys/random.h... yes
-checking sys/resource.h usability... yes
-checking sys/resource.h presence... yes
 checking for sys/resource.h... yes
-checking sys/select.h usability... yes
-checking sys/select.h presence... yes
 checking for sys/select.h... yes
-checking sys/sendfile.h usability... yes
-checking sys/sendfile.h presence... yes
 checking for sys/sendfile.h... yes
-checking sys/socket.h usability... yes
-checking sys/socket.h presence... yes
 checking for sys/socket.h... yes
-checking sys/syscall.h usability... yes
-checking sys/syscall.h presence... yes
 checking for sys/syscall.h... yes
-checking sys/sysmacros.h usability... yes
-checking sys/sysmacros.h presence... yes
 checking for sys/sysmacros.h... yes
-checking sys/time.h usability... yes
-checking sys/time.h presence... yes
 checking for sys/time.h... yes
-checking sys/times.h usability... yes
-checking sys/times.h presence... yes
 checking for sys/times.h... yes
-checking sys/uio.h usability... yes
-checking sys/uio.h presence... yes
 checking for sys/uio.h... yes
-checking sys/utime.h usability... no
-checking sys/utime.h presence... no
 checking for sys/utime.h... no
-checking syscall.h usability... yes
-checking syscall.h presence... yes
 checking for syscall.h... yes
-checking time.h usability... yes
-checking time.h presence... yes
 checking for time.h... yes
-checking ucontext.h usability... yes
-checking ucontext.h presence... yes
 checking for ucontext.h... yes
-checking utime.h usability... yes
-checking utime.h presence... yes
 checking for utime.h... yes
-checking x86intrin.h usability... yes
-checking x86intrin.h presence... yes
 checking for x86intrin.h... yes
-checking gmp.h usability... no
-checking gmp.h presence... no
-checking for gmp.h... no
+checking for gmp.h... yes
+checking for library containing __gmpz_init... -lgmp
 checking for special C compiler options needed for large files... no
 checking for _FILE_OFFSET_BITS value needed for large files... no
 checking whether byte ordering is bigendian... no
@@ -285,7 +177,7 @@
 checking for inline... inline
 checking for working volatile... yes
 checking for typeof syntax and keyword spelling... typeof
-checking for C/C++ restrict keyword... __restrict
+checking for C/C++ restrict keyword... __restrict__
 checking for long long... yes
 checking for off_t... yes
 checking char bit... 8
@@ -331,7 +223,7 @@
 checking for DEPRECATED_BY function attribute... __attribute__ ((__deprecated__("by "#n))) x
 checking for NOINLINE function attribute... __attribute__ ((__noinline__)) x
 checking for ALWAYS_INLINE function attribute... __attribute__ ((__always_inline__)) x
-checking for NO_SANITIZE function attribute... x
+checking for NO_SANITIZE function attribute... __attribute__ ((__no_sanitize__(san))) x
 checking for NO_SANITIZE_ADDRESS function attribute... __attribute__ ((__no_sanitize_address__)) x
 checking for NO_ADDRESS_SAFETY_ANALYSIS function attribute... __attribute__ ((__no_address_safety_analysis__)) x
 checking for WARN_UNUSED_RESULT function attribute... __attribute__ ((__warn_unused_result__)) x
@@ -339,8 +231,8 @@
 checking for ERRORFUNC function attribute... __attribute__ ((__error__ mesg)) x
 checking for WARNINGFUNC function attribute... __attribute__ ((__warning__ mesg)) x
 checking for WEAK function attribute... __attribute__ ((__weak__)) x
-checking for __attribute__((__depreacted__(msg))) in C++... no
-checking for std::nullptr_t... no
+checking for __attribute__((__depreacted__(msg))) in C++... yes
+checking for std::nullptr_t... yes
 checking for FUNC_STDCALL function attribute... x
 checking for FUNC_CDECL function attribute... x
 checking for FUNC_FASTCALL function attribute... x
@@ -354,7 +246,8 @@
 checking for RUBY_FUNC_NONNULL function attribute... __attribute__ ((__nonnull__(n))) x
 checking for function name string predefined identifier... __func__
 checking if enum over int is allowed... yes
-checking whether sys_nerr is declared... yes
+checking for gcc options needed to detect all undeclared functions... none needed
+checking whether sys_nerr is declared... no
 checking whether getenv is declared... yes
 checking for size_t... yes
 checking size of size_t... 8
@@ -413,6 +306,8 @@
 checking size of ssize_t... 8
 checking for printf prefix for int64_t... NONE
 checking for stack end address... __libc_stack_end
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
 checking for uid_t in sys/types.h... (cached) yes
 checking type of array argument to getgroups... gid_t
 checking for working alloca.h... yes
@@ -440,13 +335,8 @@
 checking for strlcpy... no
 checking for strstr... yes
 checking for tgamma... yes
-checking sys/pstat.h usability... no
-checking sys/pstat.h presence... no
 checking for sys/pstat.h... no
 checking for pid_t... (cached) yes
-checking vfork.h usability... no
-checking vfork.h presence... no
-checking for vfork.h... no
 checking for fork... yes
 checking for vfork... yes
 checking for working fork... yes
@@ -514,7 +404,7 @@
 checking for isfinite... no
 checking for issetugid... no
 checking for killpg... yes
-checking for lchmod... no
+checking for lchmod... yes
 checking for lchown... yes
 checking for link... yes
 checking for llabs... yes
@@ -591,8 +481,6 @@
 checking for __sinpi... no
 checking for statx... yes
 checking if getcwd allocates buffer if NULL is given... yes
-checking crypt.h usability... yes
-checking crypt.h presence... yes
 checking for crypt.h... yes
 checking for struct crypt_data.initialized... yes
 checking for __builtin_alloca_with_align... yes
@@ -659,27 +547,17 @@
 checking for getcontext... yes
 checking for setcontext... yes
 checking if fork works with pthread... yes
-checking sys/user.h usability... yes
-checking sys/user.h presence... yes
 checking for sys/user.h... yes
 checking whether PAGE_SIZE is compile-time const... yes
 checking ioctl request type... unsigned long
 checking whether ELF binaries are produced... yes
-checking elf.h usability... yes
-checking elf.h presence... yes
 checking for elf.h... yes
-checking elf_abi.h usability... no
-checking elf_abi.h presence... no
 checking for elf_abi.h... no
 checking for uncompress in -lz... yes
-checking mach-o/loader.h usability... no
-checking mach-o/loader.h presence... no
 checking for mach-o/loader.h... no
 checking whether OS depend dynamic link works... yes
 checking for backtrace... yes
 checking for broken backtrace... no
-checking valgrind/memcheck.h usability... no
-checking valgrind/memcheck.h presence... no
 checking for valgrind/memcheck.h... no
 checking for strip flags... -S -x
 checking whether -fPIE is accepted as CFLAGS... yes
@@ -692,8 +570,6 @@
 checking for sigsetjmp as a macro or function... no
 checking for setjmp type... __builtin_setjmp
 checking for prefix of external symbols... NONE
-checking pthread.h usability... yes
-checking pthread.h presence... yes
 checking for pthread.h... yes
 checking if make is GNU make... yes
 .ext/include/x86_64-linux/ruby/config.h updated
@@ -704,7 +580,7 @@
 ---
 Configuration summary for ruby version 3.1.0
 
-   * Installation prefix: /home/chkbuild/chkbuild/tmp/build/20210908T123006Z
+   * Installation prefix: /home/chkbuild/chkbuild/tmp/build/20210908T120006Z
    * exec prefix:         ${prefix}
    * arch:                x86_64-linux
    * site arch:           ${arch}

Not sure what is the practical impact other than that the OpenSUSE CI is going break once it update to Autoconf 2.71, because there is not C++ compiler installed (and something similar already happened on Fedora 3, that is why I am looking into this).

Updated by vo.x (Vit Ondruch) over 3 years ago

BTW I assume, that the AC_PROG_CC_C99 check was removed due to the following message:

$ autoconf 
configure.ac:207: warning: The macro `AC_PROG_CC_C99' is obsolete.
configure.ac:207: You should run autoupdate.
./lib/autoconf/c.m4:1659: AC_PROG_CC_C99 is expanded from...
configure.ac:207: the top level

But I think the correct fix would be to use just AC_PROG_CC according to the release notes 1, because I'd find strange that C applications would not check for C compiler on the first place.

Updated by jaruga (Jun Aruga) about 3 years ago

Here are the reproducing steps on the latest master branch 0182bf615a6ef3fb0401a31b4f6840221af00db7. I even couldn't run the ./configure. Am I missing something?

$ cat /etc/fedora-release
Fedora release 36 (Rawhide)

$ git clean -fdx

$ autoconf --version
autoconf (GNU Autoconf) 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+/Autoconf: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David J. MacKenzie and Akim Demaille.

$ autoconf
configure.ac:4281: warning: AC_C_BIGENDIAN should be used with AC_CONFIG_HEADERS

$ echo $?
0

$ ./configure
configure: error: cannot find required auxiliary files: config.guess config.sub

$ echo $?
1

Updated by vo.x (Vit Ondruch) about 3 years ago

jaruga (Jun Aruga) wrote in #note-2:

$ ./configure
configure: error: cannot find required auxiliary files: config.guess config.sub

If you were using official tarball, the config.* would be provided via make-snapshot:

https://github.com/ruby/ruby/blob/master/tool/make-snapshot#L324

Not sure what is the official way to obtain these for the Git cloned repo other then cp tool/config.{guess,sub} .. Maybe you can explore some CI scripts ...

Updated by xtkoba (Tee KOBAYASHI) about 3 years ago

jaruga (Jun Aruga) Try

$ ./autogen.sh

(See also #17723.)

Updated by jaruga (Jun Aruga) about 3 years ago

On the master branch 0182bf615a6ef3fb0401a31b4f6840221af00db7, the ./autogen.sh and ./configure work with autoconf 2.71!

$ autoconf --version
autoconf (GNU Autoconf) 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+/Autoconf: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David J. MacKenzie and Akim Demaille.

$ git clean -fdx

$ ./autogen.sh
configure.ac:4281: warning: AC_C_BIGENDIAN should be used with AC_CONFIG_HEADERS

$ echo $?
0

$ ./configure

$ echo $?
0

Not sure what is the official way to obtain these for the Git cloned repo other then cp tool/config.{guess,sub} .. Maybe you can explore some CI scripts ...

On our CIs, the ./autogen.sh is executed instead of autoconf. The tool/make-snapshot is not executed on the CIs.

Updated by jaruga (Jun Aruga) about 3 years ago

When a C++ compiler is not installed, the ./configure fails. Is this a expected behavior?

$ git clean -fdx

$ ./autogen.sh 
configure.ac:4281: warning: AC_C_BIGENDIAN should be used with AC_CONFIG_HEADERS

$ which g++
/usr/bin/which: no g++ in (/builddir/.local/bin:/builddir/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin)

$ ./configure 
checking for ruby... false
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking target system type... x86_64-pc-linux-gnu
checking for gcc... gcc
checking for ld... ld
checking for gcc-ar... gcc-ar
checking for g++... no
checking for gcc-nm... gcc-nm
checking for gcc-ranlib... gcc-ranlib
checking for g++... no
checking for c++... no
checking for gpp... no
checking for aCC... no
checking for CC... no
checking for cxx... no
checking for cc++... no
checking for cl.exe... no
checking for FCC... no
checking for KCC... no
checking for RCC... no
checking for xlC_r... no
checking for xlC... no
checking for clang++... no
checking whether the C++ compiler works... no
configure: error: in `/mnt/git/ruby/ruby2':
configure: error: C++ compiler cannot create executables
See `config.log' for more details

I see the following logic that is to pass the script if the C++ compiler doesn't exist?

AS_IF([test -n "${rb_there_is_in_fact_no_gplusplus_but_autoconf_is_cheating_us}"], [
    AC_MSG_NOTICE([Test skipped due to lack of a C++ compiler.])
],

Updated by jaruga (Jun Aruga) about 3 years ago

When a C++ compiler is not installed, the ./configure fails. Is this a expected behavior?

Ah now I see the C++ compiler requirement happens with autoconf 2.71 but it doesn't happen with autoconf 2.69.

Updated by shyouhei (Shyouhei Urabe) about 3 years ago

jaruga (Jun Aruga) wrote in #note-7:

When a C++ compiler is not installed, the ./configure fails. Is this a expected behavior?

Ah now I see the C++ compiler requirement happens with autoconf 2.71 but it doesn't happen with autoconf 2.69.

I guess this is because AC_PROG_CC_C99 is deleted. There must be either C or C++ compiler, but 2.71 doesn't check for C.

As @vo.x (Vit Ondruch) says in comment #note-1, we must call AC_PROG_CC somewhere.

Updated by jaruga (Jun Aruga) about 3 years ago

As vo.x (Vit Ondruch) says in comment #note-1, we must call AC_PROG_CC somewhere.

I see the following git|912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 now. Thanks. Now I see the following steps work on the commit 912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6 with autoconf 2.71 and without a C++ compiler, though we see a warning.

$ autoconf --version
autoconf (GNU Autoconf) 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+/Autoconf: GNU GPL version 3 or later
<https://gnu.org/licenses/gpl.html>, <https://gnu.org/licenses/exceptions.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by David J. MacKenzie and Akim Demaille.

$ git clean -fdx

$ ./autogen.sh
configure.ac:4281: warning: AC_C_BIGENDIAN should be used with AC_CONFIG_HEADERS

$ ./configure
Actions #10

Updated by nobu (Nobuyoshi Nakada) about 3 years ago

  • Status changed from Open to Closed

Applied in changeset git|ca3cc677b31897e7306ac3b4565a0dd928168b08.


Define ACTION-IF-UNIVERSAL of AC_C_BIGENDIAN [Bug #18156]

As we do not use config.h.in, just define the helper macro
instead.

Updated by jaruga (Jun Aruga) about 3 years ago

Thank you for the patch to fix the warning about AC_C_BIGENDIAN.

For the patch 912a8dcfc5369d840dcd6bf0f88ee0bac7d902d6, I guess the patch is required to use autoconf >= 2.70, as autoconf 2.71 is a stable bug fix release. Maybe I saw the release note URL introduced by @vo.x (Vit Ondruch) somewhere, but I forgot where I saw it. So, I would reintroduce the URL here again.

https://lwn.net/Articles/839395/

GNU Autoconf 2.70 released
...
*** Setting CC to a C++ compiler is no longer supported.

*** AC_PROG_CC_STDC, AC_PROG_CC_C89, AC_PROG_CC_C99 are now obsolete.

Applications should use AC_PROG_CC.

https://lists.gnu.org/archive/html/info-gnu/2021-01/msg00017.html

autoconf-2.71 released [stable]

2.71 is a bugfix release, correcting several important compatibility
problems and regressions discovered since the release of 2.70. There
are no new features.

Actions #12

Updated by nobu (Nobuyoshi Nakada) about 2 years ago

  • Backport changed from 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN to 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: REQUIRED
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like1Like0Like0Like0Like0Like0Like0Like0Like0