This is the fifth day of my participation in the August More text Challenge. For details, see:August is more challenging

In a recent review of the Linux API for Time processing, when localtime_r and clock_gettime are used in the development library, the following error is displayed (-werror option is enabled) :

Error: Implicit declaration of function 'localtime_r' [-werror =implicit function-declaration]Copy the code

Solving steps

Doubt the GCC version

The project build tool used by the development library is cmake, which is a weird problem because there was no problem writing small test programs before. Cmake is not using the correct version of GCC. The following is a possible way to modify the compiler: Add the following code to build.sh:

COMPILE_PATH="-DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc"
cmake . $COMPILE_PATH
Copy the code

DCMAKE_CXX_COMPILER is used to specify the path g++, and CMAKE_C_COMPILER is used to specify the path GCC.

Cmake: the GCC configuration has been changed.

You have changed variables that require your cache to be deleted. Configure will be re-run and you may have to reset some variables. The following variables have changed: CMAKE_CXX_COMPILER= /usr/bin/gcc CMAKE_CXX_COMPILER= /usr/bin/g++ -- The C compiler identification is GNU 4.8.4 -- The CXX Compiler Identification is GNU 4.8.4 -- Check for working C compiler: /usr/bin/gcc -- Check for working C compiler: /usr/bin/gcc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/g++ -- Check for working CXX compiler: /usr/bin/g++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating doneCopy the code

However, the compiler still prompts the same error, which appears to be incorrect cmake and GCC.

Cmake minimum project

It is not the GCC version that is the problem, now only the cmake environment and the development library environment are left, first test the cmake minimum project to see if it can be compiled (note that you need to use the same cMakelists.txt configuration).

The project directory is actually very simple. It just contains cmakelists. TXT and a C source file.

#CMakeLists.txt: Project (emlib) add_compile_options(-std=c99 -werror) set(CMAKE_CFLAGS_DEBUG "$ENV{CFLAGS} -O0 -Wall -g -ggdb -fstack-protector-all") set(CMAKE_CFLAGS_RELEASE "$ENV{CFLAGS} -o3-wall -dndebug ") # Find all source files in SRC directory and store them in the DIR_SRCS variable aux_source_directory(.dir_srcs) # Configure the directory where header files are stored Include_directories (/usr/include/) # generate target add_executable(${PROJECT_NAME} ${DIR_SRCS}) # Configure link libraries target_link_libraries(${PROJECT_NAME} pthread)Copy the code
test.c

#include <time.h>
int main(void)
{
	struct tm rs; 
    time_t tp; 
    time(&tp);

    localtime_r(&tp, &rs); 
	return 0;
}
Copy the code

Compile the test, and the problem remains. There you have it: cmake has a configuration problem. However, as you can see, the cmake configuration is fairly simple. Which configuration affects the Linux library?

One good thing came out of

Just as the problem was running into trouble, it occurred to me that cmake supports the ability to generate various compiled files. Why not take a look at the precompiled file of the source file and see why the localtime_r function was not declared? C is not included in the localtime_r declaration in time.h.

H file is located in /usr/include/time.h.

# if defined __USE_POSIX || defined __USE_MISC
/* Return the `struct tm' representation of *TIMER in UTC,
   using *TP to store the result.  */
extern struct tm *gmtime_r (const time_t *__restrict __timer,
                struct tm *__restrict __tp) __THROW;

/* Return the `struct tm' representation of *TIMER in local time,
   using *TP to store the result.  */
extern struct tm *localtime_r (const time_t *__restrict __timer,                                                                                                                                             
                   struct tm *__restrict __tp) __THROW;
# endif /* POSIX or misc */
Copy the code

Obviously, localtime_r is only declared when __USE_POSIX and __USE_MISC macros are defined! So why doesn’t GCC define these macros?

Looking back at the cmakelists.txt file, I found that only add_compile_options(-std= c99-werror) changed the compiler options, commented it out, recompiled it, and passed.

For int I = 0; for int I = 0; i < N; I++)), which standards should be used to support some of the newer compiler features?

C standard

By querying, we found that there have been many C related standards in history, as shown in the following table:

The major version C89 AMD1 C99 C11
The alias C90 、ANSI C、 X3.159-1989 、ISO/IEC 9899:1990 C94 、C95 ISO/IEC 、9899:1999 ISO/IEC 、9899:2011
Standard passage time
Standard release Time In 1990, In 1995, In 1999, In 2011,
GCC uses the parameters used for this version -ansi -std=c90 -std=iso9899:1990 -std=iso9899:199409 -std=c99 -std=iso9899:1999 -std=c11 -std=iso9899:2011
Parameter used when GCC uses this version with C extensions -std=gnu90 -std=gnu99 -std=gnu11

Since we are using GCC, -std=c99 should be changed to -std=gnu99, and the compile test passes.

For example, macros like _USE_POSIX and _USE_POSIX are defined under the GNU standard. GCC uses the GNU standard by default. So if you are developing on the GNU/Linux platform using GCC, if you need to specify C standards, you should use GNU related standards.

Afterword.

As you can see, the problem in this article is not a particularly difficult programming problem, but simply a problem with compiler options. But why make such a detailed summary? In fact, the problem itself is not important, the important is the solution to the problem. This article actually shows a basic step to solve the problem:

  1. First, analyze the appearance of the problem. If it is not easy to locate the cause of the problem, then we should solve it step by step.
  2. Identify the domains of possible causes of the problem and rank them in order of likelihood, the most likely certainly to need to be addressed first;
  3. Then, according to the cause domain, stripe test, one by one, until the problem is solved;
  4. If, after testing all the cause areas, the problem is not solved, then there may be a missing situation in the cause area or the direction of the problem analysis is wrong or the problem phenomenon is not analyzed thoroughly…
  5. Repeat Step 2 and step 3 to redefine the cause domain.

In fact, no matter big or small, we should analyze and solve the problems in a scientific way and with a cool head. We should believe that as long as we are willing to use our brains, the solutions are always more than the difficulties.