Skip to content

make check doesn't pick up changes to the code #4803

Closed

Description

@egmontkob

Is there an existing issue for this?

  • I have searched the existing issues

Midnight Commander version and build configuration

current git (fab4f6b7e)

Operating system

Linux

Is this issue reproducible using the latest version of Midnight Commander?

  • I confirm the issue is still reproducible with the latest version of Midnight Commander

How to reproduce

Discovered while working on #4801 / #4802.

make && make check still runs the unittest against the previous code.

Start with buggy code. Add a new unittest (to tests/lib/terminal.c) that should pass. make && make check fails as expected.

Fix the code (in lib/terminal.c). Run make && make check. Fails (unexpected).

Either do a make clean, or touch the unittest file. Now make && make check succeeds as expected.

The same story the other way around:

Now revert the code back to the old, buggy version. make && make check => success (unexpected).

make clean or touch the unittest file. make && make check => failure (as expected).

The test infrastructure doesn't pick up changes to the actual code if the unittest wasn't touched.

Expected behavior

.

Actual behavior

.

Additional context

No response

Activity

  1. added theissue type on Oct 19, 2025
  2. added
    area: buildBuild system and (cross-)compilation
    and removed
    needs triageNeeds triage by maintainers
    on Oct 20, 2025
  3. zyv commented on Oct 20, 2025

    @zyv
    Member

    TLDR; try a completely clean, fresh build with --disable-mclib and hopefully this simply fixes the issue.

    If not, then there is some hole in the dependency chain that should be plugged, even though I thought I've already caught most of those.


    Now, this is going to be an unexpectedly long one, so, kids, get yourself comfortable around the campfire and your marshmallows ready... and just ignore this shrieking of hungry wolves in the distance, as long as the fire is burning they won't dare to attack us. At least for now...


    So normally, autotools (and make) will track the dependency chain of the target, and shall one of those dependencies change, the targets in-between are going to be re-run. You achieve this by listing the source files in the appropriate variables, or else you can do globbing, which comes with its own host of problems.

    In this case, however, I don't think that missed targets are to be seen, and yet I also remember encountering similar issues in the past, where test targets were not rebuilt according to the changes in the source code, and even more strangely, the mc binary itself. You can check if this also happens to you when you have the issue with the test.


    I think I've tracked it down to the mclib story.

    Basically, you can have a normal C program not involving any libraries built using autotools. In this case, the dependency chain is quite straightforward - the source or header files change - and so the binary has to be re-assembled from object files, not all of which can be re-used, and so will have to be recompiled.

    Then you can take the next step and bundle object files in internal library archives and build the binaries out of those. This would make sense for big pieces of software producing multiple binaries from overlapping groups of source files, which take a lot of time to re-compile and re-assemble.

    Finally, you can go even further and use shared libraries, which are basically stand-alone and not integrated in the final binary, but rather linked to it. It is when the binary is run that the shared libraries are searched for and loaded in the address space to fill in the functions that are supposed to be coming from there.

    Now, of course, the whole thing comes with thousands of platform-dependent issues, and so a wrapper has been created called libtool, which abstracts all this stuff and makes it possible for the developer to work with "libraries" and under the hood it will do what it can to achieve the best results according to what the platform supports and what the general intention of the developers is.


    So much for the relevant theory. Now, in as far as mc is concerned, after the push to modernize the code and make the system more future-proof was initiated by Slava, one of the big refactorings (which is unfortunately not really concluded to this day) was to split the code into cleaner internal libraries and introduce interfaces between pieces that don't necessarily need to depend on each other.

    This is generally a great thing and makes working with the code easier, builds times faster, and tests simpler because the functions are less intertwined with each other. But it didn't stop there. The idea was to enable the enhancement of the functionality of mc with plugins, which developers could create independently using published interfaces and then distribute as shared libraries, which mc would be able to load.

    In this specific case, the notion came from FAR, which initially started as closed-source software, and thus it wasn't simply possible to patch FAR to add a new worthwhile feature, even if it were to be deemed reasonable to accept it into the core. So it had a plugin API, which third-party developers could use to create their own plugin libraries. These libraries were then loaded by FAR, and so it went.

    So, in addition to refactoring the source code of mc to make it modular, something called mclib was introduced via libtool, which was eventually supposed to be the part of mc that external plugins would be allowed to interact with or external programs using mc as a library could use.

    At this point, you might ask whether I'm confounding two issues:

    1. Make it possible for mc to load plugins.
    2. Make it possible for other software to use parts of mc as a library.

    Unfortunately, not really, but getting into that would require a couple more days of typing.

    In brief, the issue lies around the shared library loading and symbol resolution. Yes, you would normally load plugins using dlopen and call their functions, but for plugins to access your stuff, which somehow appeared desirable, you need some other solution. You can merge the symbol space and pick up all problems that come with it, or you can back-link your plugins to your shared libraries (I'm not kidding), which is generally much more reliable and less problematic on Linux. It's the latter point, I think, which gave birth to mclib in its current form, unless it was simply a cargo cult perpetuated by the plugin systems of other Linux software.

    In any case, if you change some part of the code that belongs to the "library" and if you compile with --enable-mclib, you have that part of the code isolated into a shared library which is linked to the mc binary and test binaries.

    Unfortunately, the dependency tracking is not working correctly in this case. I'm not exactly sure what is not working there, because in theory, it should be possible to get it to work, but obviously, something isn't working, and honestly, I'm convinced that it's not even worth tracking down and fixing this.


    Instead, I'm of the opinion that we should completely remove all that mclib garbage.

    I'm not even sure that if we do that, we'll even need libtool at all. Yes, we could still use libtool for internal libraries (basically packing o-files into a-files, and building mc binary out of a-files instead of o-files). This could save some time re-packing the binary if just a few o-files change. However, with our code base size and the power of modern systems, I'm quite convinced that the build performance might actually improve if we just ditch libtool completely (and switch to a non-recursive mode of autotools where possible).

    We can separate our code into clean non-intertwined sub-libraries just the same, no matter how we built id. And in as far as the extensibility story goes, the plugins are simply a bad idea. Instead, we should isolate mc core and provide an execution engine for user scripts like @mooffie did in the awesome mc^2 project. One can argue whether Lua is the best choice, and I personally would lean towards re-writing the core in Rust and providing an ECMAScript execution engine to leverage its infrastructure, but that's a different discussion.

    Looking back at FAR, it was quite understandable how and why it ended with plugins, and plugins are what made it rule the world, but ironically, the latest version of FAR has actually drifted away from this model after it was open-sourced. These days, FAR features a Lua-based execution engine (hello, mc^2!) and most new stuff happens there. The incredible amount of plugins has now been greatly shrunk with the most valuable ones now being maintained in the core and a few other popular ones outside. But it's nothing like it was in the proprietary days, and they are where they are just because such things don't die (quickly).

  4. egmontkob commented on Oct 20, 2025

    @egmontkob
    ContributorAuthor

    TLDR; try a completely clean, fresh build with --disable-mclib and hopefully this simply fixes the issue.

    Nope, it doesn't.

  5. egmontkob commented on Oct 20, 2025

    @egmontkob
    ContributorAuthor

    Thanks for the explanation!

    honestly, I'm convinced that it's not even worth tracking down and fixing this

    This part I understand and I feel for you. If we can't fix this bug then we can easily live with it, no problem. At least we have it documented now.

    As for autotools / libtool... I get some rough idea. I'm not familiar with the details of these software, all that I know is I had much more trouble with them through my decades of Linux development than I wished for. The recent xz-utils backdoor should have been the last nail in its coffin (well, in the coffin of the idea of shipping anything autogenerated / not VC-tracked in the release tarball).

    What could be done?

    Switch to cmake? I had some closer encounter with that and I never managed to properly understand what's going on there, setting up dependencies was always a nightmare to me.

    Switch to meson / ninja? #3946 I haven't had problems with it yet. I'm hoping that reason for this is not that I just never got really close to it, never really wrote dependency rules. My overall impression is that it sucks less than autotools or cmake. Also, GLib needs meson / ninja to build and mc needs GLib, so it's a fair game to expect it to be available on all systems that we support.

    But I understand that it might be just too much work and simply not worth it.

  6. zyv commented on Oct 20, 2025

    @zyv
    Member

    TLDR; try a completely clean, fresh build with --disable-mclib and hopefully this simply fixes the issue.

    Nope, it doesn't.

    Well, in this case, we're in luck (or maybe not, depending on how you see it).

    Apparently, something is missing in the dependency chain, and maybe can be even fixed more or less trivially? To investigate that, one needs a stable reproducer, that is, which file is updated, but doesn't cause the test to be rebuilt. I see you put it in the description, and I could indeed get it to (not) work.

    What happens if you try the following patch? Obviously, you have to regenerate the build system, reconfigure, and recompile for that to take effect.

    diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am
    index e66688dbb..47098214f 100644
    --- a/tests/lib/Makefile.am
    +++ b/tests/lib/Makefile.am
    @@ -4,8 +4,9 @@ SUBDIRS = . mcconfig search strutil vfs widget
     
     AM_CPPFLAGS = $(GLIB_CFLAGS) -I$(top_srcdir) @CHECK_CFLAGS@
     
    -LIBS = @CHECK_LIBS@ \
    -       $(top_builddir)/lib/libmc.la
    +LDADD = $(top_builddir)/lib/libmc.la
    +
    +LIBS = @CHECK_LIBS@
     
     if ENABLE_MCLIB
     LIBS += $(GLIB_LIBS) \
  7. zyv commented on Oct 20, 2025

    @zyv
    Member

    This part I understand and I feel for you. If we can't fix this bug then we can easily live with it, no problem. At least we have it documented now.

    As for autotools / libtool... I get some rough idea.

    Well, my rant wasn't so much about autotools as such, but more about wrong design decisions and a misguided use thereof, which doesn't make sense and causes problems.

    What could be done?

    In as far as mclib goes, I have hopefully made myself clear:

    1. The nonsense to produce a shared library out of it has to be removed from the codebase.
    2. The strategic direction should be an integration of an execution engine for extensibility.

    Regarding autotools, I used to hate them, but this was mainly caused by several factors:

    1. General ignorance regarding the workings of compilers, linkers, library loading, etc.
    2. Lack of understanding of the autotools ecosystem itself.

    The more I learned, the more I've got to appreciate why and how things evolved, even though I still don't agree with all decisions; it just does make much more sense on the whole.

    So these days, I'm actually much more positive about autotools as compared to other build systems for C/C++ which mostly get born as people hating autotools out of ignorance rather than deep understanding are trying to make something new and better without actually knowing too much about what they are doing.

    Same with programming languages, actually, how many billions do we have already? Every engineer at some point thinks he's got it and will make something that is really great and not suffer from all the problems his stupid predecessors weren't able to solve... and with extremely rare exceptions, yet another garbage language is born.

    So my approach would be to clean up our autotools build system such that it works correctly. I can't claim I'm an expert now, but there are 3 excellent sources of information one can refer to:

    1. Autotools: A Practioner's Guide to GNU Autoconf, Automake, and Libtool by John Calcote
    2. Autotools Mythbuster by Diego Elio “Flameeyes” Pettenò
    3. GNU documentation for Autotools, etc.

    If you understand and follow their best practices, it mostly works just fine. I think I've done a lot in this direction so far. It’s just that I'm not quite there yet...

  8. egmontkob commented on Oct 20, 2025

    @egmontkob
    ContributorAuthor

    What happens if you try the following patch?

    Yup, this works for me! 👍 Thanks!! :)

  9. added a commit that references this issue on Oct 20, 2025
  10. modified the milestones: Future Releases, 4.8.34 on Oct 20, 2025
  11. modified the milestones: 4.8.34, 4.8.35 on Jan 25, 2026
  12. added a commit that references this issue on Oct 17, 2026
  13. modified the milestones: 4.9.1, 4.9.0 on Oct 17, 2026
  14. added 3 commits that reference this issue on Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: buildBuild system and (cross-)compilationprio: mediumHas the potential to affect progress

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions