Re: Discussion about why GNU/Linux system upgrades cause old programs to break
Arsen Arsenović <[email protected]>
| Newsgroups | gmane.emacs.devel |
|---|---|
| Message-ID | <[email protected]> |
Eli Zaretskii <[email protected]> writes: >> From: Arsen Arsenović <[email protected]> >> Cc: Eli Zaretskii <[email protected]>, [email protected], [email protected] >> Date: Wed, 12 Aug 2026 19:31:09 +0200 >> >> /tmp/emacs-24.1/lib-src/emacsclient.c: In function ‘main’: >> /tmp/emacs-24.1/lib-src/emacsclient.c:1606:9: error: implicit declaration of function ‘get_current_dir_name’ [-Wimplicit-function-declaration] >> 1606 | cwd = get_current_dir_name (); >> | ^~~~~~~~~~~~~~~~~~~~ >> /tmp/emacs-24.1/lib-src/emacsclient.c:1606:7: error: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion] >> 1606 | cwd = get_current_dir_name (); >> | >> >> The latter is a case where Emacs blatantly violates the rules of C99: it >> calls a function that is not declared. > > First, Emacs 24 was not a C99 program. Then its build system broken. It passes -std=gnu99 to the compiler when given a C89 compiler. > We switched to C99 in Emacs 25.1, see NEWS.25. So no, the above was > not a violation of the C standard we were adhering to back then, > certainly not a "blatant" violation. I'm old enough to remember the > old C rules, whereby a function without a prior declaration > (a.k.a. "prototype") had very specific semantics for its return type. Those semantics are wrong for this case, thereby demonstrating what I said: a program that runs into these errors is very unlikely to be correct. The guessed function declaration has an int return type, as I'm sure you know, but the return type is char*. This may accidentally work on IP32 machines, but it does not work on any other system, including mine. > And second, I don't really understand the above warnings at all, > because emacsclient.c in Emacs 24.1 says this starting at line 232, > way before line 1606: > > char *get_current_dir_name (void); > > /* Return the current working directory. Returns NULL on errors. > Any other returned value must be freed with free. This is used > only when get_current_dir_name is not defined on the system. */ > char* > get_current_dir_name (void) > { That's under a preprocessor condition which, when unmet, also obscures the declaration above it. When it is unmet, the definition is in another TU and no declaration exists in this TU. >> Unfortunately, that's not at all a simple answer, especially not for an >> old codebase. If I kept attempting to fix the above, I'm sure I'd have >> ran into many more problems. > > I'm sure you would. And I would naïvely ask: why shouldn't we have an > easily-discoverable option to avoid such problems when we need to > compile old source code? There's no such thing as an "easily-discoverable option to avoid such problems". If there was, people wouldn't fix it by pinning versions in the way I described before. If there was, I'd have suggested it. That said, for the particular case of the GCC 14 changes, which were under discussion but are *not* what I was referring to above, I think making -fpermissive or -std=gnu89 easier to find would be good. I'm not sure how best to go about it, though. We already document it in the release notes for GCC 14: https://gcc.gnu.org/gcc-14/porting_to.html#errors-as-warnings And, of course, in the manual. Perhaps it warrants some new index entries, or some new prose in the (gcc) Standards page. >> > Would there be a subset of dependencies such that there is greater >> > longevity anticipated for, by way of illustration, Emacs compiled >> > without GTK. Namely, a subset of e.g. terminal-based Emacs? >> >> I certainly expect Emacs compiled with fewer dependencies to live for >> longer, because that means, by proxy, that it is smaller. > > That's impractical to expect. What I said is certainly not wrong to expect, but I think there's a misunderstanding, because, ... > People expect Emacs to do everything including coffee, so most of the > users want as rich Emacs as possible, not as lean as possible. ... is indeed true. I didn't suggest that Emacs should be lean by default. I also didn't suggest arbitrarily reducing program size as a solution. What I said is that Emacs compiled with fewer dependencies (and thus with fewer features, and thus with less code) is less likely to break. > And anyway, some compatibility problems are in system libraries such > as libc and basic GUI stuff, and those dependencies cannot be removed > from Emacs. Indeed, but obviously the fewer there are, the fewer breaks happen. libc has fairly few real breaks, for instance. >> >>> See above: that's not what happens. In reality, the build invokes the >> >>> compiler without specifying the dialect, so whatever is the default C >> >>> dialect is being used. So when the default changes to be >> >>> backward-incompatible, it's bound to break old programs. >> >> >> >> Indeed, the default dialect can change. This is why I find the >> >> autotools choice to only provide -std=... conditionally dubious. >> > >> > Do you have a suggestion to improve this? >> >> Yes. Pass it always when possible, ensure that it has an effect. >> >> I've seen some projects do the following for C++: >> >> AC_DEFUN([NMS_CXX_11], >> [AC_MSG_CHECKING([whether $CXX is for C++11]) >> AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ >> [#if __cplusplus != 201103 >> #error "C++11 is required" >> #endif >> ]])], >> [AC_MSG_RESULT([yes])], >> [CXX_ORIG="$CXX" >> CXX="$CXX -std=c++11" >> AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ >> [#if __cplusplus != 201103 >> #error "C++11 is required" >> #endif >> ]])], >> AC_MSG_RESULT([adding -std=c++11]), >> [CXX="$CXX_ORIG" >> AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ >> [#if __cplusplus > 201103 >> #error "C++11 is required" >> #endif >> ]])], >> AC_MSG_RESULT([> C++11]), >> AC_MSG_RESULT([no]) >> AC_MSG_ERROR([C++11 is required])])) >> unset CXX_ORIG])]) >> >> ... i.e. ensure that the compiler is *truly* a C++11 compiler, at least >> by adding -std=c++11. >> >> Analogously this goes for every C version. > > That's harsh: it requires one to install a compiler that adheres to > the particular version of the standard even if that is not required by > the code. This was written for a program that very specifically requires a C++11 compiler. Newer versions could work also, but, if the program was to, say, switch to C++17 automatically without using any C++17 features even opportunistically, it'd open itself up to any language changes made in C++17, without having been tested for that version. Thus, it'd be more likely to break. For no benefit, as it can't exploit any new features, because the author didn't write any code that could exploit such features. This is not C++-specific either, C23 for instance makes 'bool' a keyword. That's somewhat unlikely to break programs, but it still can. Note that any C++XY where XY>11 compiler also provides C++11 with a matching compatibility mode. The same is true for C. > We in Emacs use a different approach: we use features from newer > standards when they are available, and have workarounds and > replacements for when they are not. This is why our configure script > checks for various -std=gnuXX and -std=cXX options, starting from the > most advanced one and going back to the oldest one we want to support, > and uses the first one that's supported (and compiles the test program > with features from that version of the standard). Sure. And the build system should always specify one in the end. This is not at all contradicting what I said. If you're testing your program against C99, C11, C17 and C23, that's perfectly fine, but always pass at least one of those via the -std= flag, if any such flag is supported. This does not inhibit (attempting to) build the program on any compiler that lacks such a switch, but also makes sure you're not sensitive to changes in the default -std= value. It reduces the possible language versions you're building against to the ones you're testing against. It follows that your users' configurations are hence closer to the configuration you actually develop for. It follows that breakage is less likely. -- Arsen Arsenović
signature.asc
(application/pgp-signature, 418 B)
-----BEGIN PGP SIGNATURE----- iQECBAEWCgCqFiEE/uKz0RP8AKMWLWBhUsKUMB6ixJMFAmp+LIwbFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25z Lm9wZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRGRUUyQjNEMTEzRkMwMEEzMTYyRDYw NjE1MkMyOTQzMDFFQTJDNDkzEBxhcnNlbkBhYXJzZW4ubWUACgkQUsKUMB6ixJPP 2gEAnAmRxjvOlj9DehvtwB95HWfpSX2NwGMwRLxBGly8a5MA/jgX2/pMfuYBix65 HMATcorAW2ISVGN/n3yfDFFwIrYH =lvIe -----END PGP SIGNATURE-----