15

I hope some Linux die-hard can answer me how I should write portable (POSIX) code when working with time functions.

  • Some SO threads suggest that including ctime would be the right thing to do when writing C++ code, whereas you would still include time.h for C code. However, they both define the same function, albeit in a different namespace. Technically you should be able to specify both.

  • One SO post suggested that one should AVOID using the sys/* based includes alltogether..

  • .. while this thread implies that sys/time.h must be included before sys/resources.h is included, in particular for BSD-based platforms.

  • This post says including sys/time.h improves portability. I imagine the poster thinks that it allows you to link more 3rd party libaries that use particular functions like gettimeofday.. however..

  • gettimeofday() has been discouraged, and is now currently enjoying deprecated status, so I should use clock_gettime() instead. This clock_gettime() is defined in time.h, see https://linux.die.net/man/3/clock_gettime..

  • .. if one installs and links with libavutil (e.g. as part of ffmpeg-dev) it becomes clear that time.h was created to drive people nuts. Ffmpeg (and some other libs) has it's own time.h, and even timeb.h. It turns out that if ANY .c or .cpp anywhere in your build stack ever includes a time.h, with the include path holding multiple valid entries (including the one for ffmpeg), it may refer to the wrong one, and the declarations are simply replaced. @ FFmpeg, the reasoning seems to be that an ugly hack is sufficient to fix the problem. I haven't been that lucky yet. Also, Php-izing all sources does not sound like a solution at all.

  • Another time.h exists in usr/include/i386-linux-gnu/bits on my system, so this isn't an ffmpeg-only phenomenon either. Simply referring to usr/include/i386-linux-gnu as an include path thus becomes deadly, which is odd when referring to system includes.

  • I've rewritten my CMake scripts, taking care to use dedicated include folder specs for most of the targets. I've tried including all sorts of permutations of time.h/ctime and sys/time.h in a precompiled header that is referred to throughout the codebase. I still get errors like:

error: field ‘st_atim’ has incomplete type ‘timespec’, struct timespec st_atim;

error: ‘::time’ has not been declared

etc..

So, for a C++ setup linking with many 3rd party dependencies, what is the correct way to make sure everything keeps compiling w.r.t. including time.h? Should I pin the time.h include for the system to the specific platform I'm compiling to? Should I go over all targets that possibly need time.h? Dancing elephants and confetti lie ahead.


Update: The issue seems to be related to the version of C++ as was hinted at in the comments below. I've since updated gcc to 8.3.0 (from 5.4), and I've given up on supporting older c++ compatibility below c++11 on linux. After updating and rebuilding all 3rd party packages (including ffmpeg), I now no longer have the issue I described, but that doesn't mean it's fixed in the sense that it can't occur again for someone else. In fact I think the issue is mainly with how ffmpeg compiles on older compilers and without c++11 explicitly requested, so I'm leaving it open.

StarShine
  • 1,940
  • 1
  • 27
  • 45
  • 3
    The correct solution is: include and fix your system. I've never had a problem. – user253751 Mar 26 '19 at 00:17
  • `` is a standard header for C. Since you're using C++, you can use either `` or ``; the difference is that the latter puts symbols into the `std` namespace. Using `` is considered better. That's for the functions and types defined in ISO standard C (and therefore also in C++). Handling of POSIX-specific-functions *might* be different (I haven't checked), but it's probably similar. There is, as far as I know, no `ctime.h` (referred to in your title). – Keith Thompson Mar 26 '19 at 04:27
  • @KeithThompson thanks for spotting the error, I fixed it in the title. – StarShine Mar 26 '19 at 09:48
  • @immibis: ok, so how do I fix my system, knowing that I want to use both the time.h of my platform and build/link with ffmpeg's libavutil? – StarShine Mar 26 '19 at 09:53
  • @StarShine libavutil's one would be – user253751 Mar 26 '19 at 22:24

1 Answers1

9

I recommend you consider Howard Hinnant's date library that has been accepted into the next version of the C++ standard library (C++20):

https://github.com/HowardHinnant/date

It should work on any platform that supports C++11 onwards.

The Standard version is documented here: https://en.cppreference.com/w/cpp/chrono

Galik
  • 47,303
  • 4
  • 80
  • 117
  • How does an upcoming C++20 feature help write portable Posix code that runs on contemporary platforms? For example, CentOS 7 or Ubuntu 18 LTS? Some VPS's are still providing Ubuntu 14 and 16 machines. – jww Mar 26 '19 at 07:55
  • 2
    @jww The library I linked to actually works on `C++11` which is quite a few years old now. The fact that it will be in the upcoming standard makes it a good choice imo because it will continue to be available in the future. However, if you (or anyone else reading this question) have a platform that does not support `C++11` then you (or they) will have to find another solution. – Galik Mar 26 '19 at 08:34
  • To the downvoter. Can you please explain the down vote? – Galik Mar 26 '19 at 08:35
  • Thanks for the suggestion, good to know something standardized is coming our way. However in this case it does not help because it's based on ctime (logical, I agree) which in turn includes time.h, and you get the same issues from there. – StarShine Mar 26 '19 at 09:52
  • @StarShine Then maybe I am not understanding your problem. You can write code without including anything but this library and perhaps ``. There is no need to include `` yourself or have anything to do with ``. The only type you may need to access in common with `` is `std::time_t`. Can you provide a minimal code example of something that fails on different `POSIX` platforms? – Galik Mar 26 '19 at 10:02
  • @Galik all that is required to reproduce my issue is to download and build ffmpeg from source and then build a program that uses system time.h functionality, and ffmpeg. In fact, Ffmpeg branched off and later on re-merged into the original, libavutil is a remnant of the intermediary fork. The ffmpeg API is already messy by itself. But I suspect the way I'm using gitlab CI to build everything is also part of my problem; I'm building wrappers for most 3rd party libs that also include system time.h, but the search paths might still be used by subsequent buillds on the same stage.. – StarShine Mar 26 '19 at 11:22
  • @StarShine So it causes a problem if you use some of the `std::` symbols? or is it `POSIX` specific functionality that causes clashes? If so which specific functionality are you unable to use? (I am unable to reproduce the problem, it seems to work fine for me so far). – Galik Mar 26 '19 at 11:38
  • @Galik Ok, my system then: I'm using LinuxMint, gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609, and install packages ffmpeg, opencl etc. If you then try to include and link with all of this, I get the undeclared symbols above. I'm generally including the time.h includes before anything else. Also note that the libavutil time.h does not match the system time.h. I'm mentioning opencl here because it seems somehow related. I had these errors fixed earlier by renaming time.h in libavutil, but they seem to have come back when I added opencl (I also upgraded the dist a few times..) – StarShine Mar 28 '19 at 08:33
  • @Galik thanks btw for trying this out for me, all info is appreciated! – StarShine Mar 28 '19 at 08:35