Gvedit: library 'util_C' not found

I am doing maintenance for Graphviz on MacPorts, trying to update from version 12, to current version 14.0.2. Part of the build is in effect, a stand-alone Autotools build of gvedit. This error hits when linking the executable.

ld: library 'util_C' not found

I see that a few references from gvedit into libutil_C were added for the first time in Graphviz version 13. My question is briefly, was something forgotten in the Autotools configuration or Makefiles for gvedit?

This build seems to be able to find other needed internal libraries such as libcdt, libcgraph, and libgvc. I notice that these other libraries were installed as permanent dylibs in a previous step, but libutil_C was not handled the same way. MacPorts removes temporary files between major build stages, so I suspect that a built libutil_C.a may have been discarded in this way.

I hope to avoid getting into the gory details of MacPorts builds or the current build patches. If you insist, build logs from one of my less radical attempts may be found here. The link error is near the end of each log.

I came upon this topic and wanted to check what the matter is, but it turned out I don’t know how to run gvedit (on Linux). @dallured or somebody? Do I have to build Graphviz with some option?

man gvedit

gives

No manual entry for gvedit

(I know that there’s the man page cmd/gvedit/gvedit.1),

./configure --help | grep -i gvedit

gives nothing, and

find / -executable -type f -iname '*gvedit*' 2>/dev/null

gives nothing.

On-line manual, very brief: gvedit | Graphviz

It says that this will display some usage instructions. I added the quoting which is necessary for your Linux command line:

gvedit '-?'

I do not have enough experience to explain how to build gvedit on Linux. For MacPorts, I am working on someone else’s scripting which hides the build command details.

After studying the makefiles some more, it looks like libutil_C has exotic structure. Therefore I think my path of least resistance is to completely sidestep that library and dependency issues, and insert an isolated source compile of lib/util/gv_find_me.c directly into the makefile for gvedit.

Any tips on how to do that cleanly would be appreciated. gvedit is all C++ sources, so I would need to figure out how to add a plain C source into the mix.

After studying the makefiles some more, it looks like libutil_C has exotic structure.

No, I was mistaken. In Graphviz, libutil_C.a is created by the ar command, which I was not expecting.

I don’t immediately know what the root cause is. But it surprises me that the build jumps immediately into building gvedit. How are any of the dependencies ready? Can we see your patches?

@smattr Under autotools, Graphviz is a single unified build for all configured options. MacPorts tries to do something unintended. It splits the build into one core build, plus two other stand-alone builds including gvedit. This split was done long ago, possibly to isolate the graphviz core from problematic dependencies such as Qt.

I think this is the root of the problem. MacPorts deletes all temporary files between these three builds. Permanent installed libraries (libcgraph etc.) are preserved, but libutil_C.a is temporary, therefore lost before the gvedit build.

My working solution is to skip libutil_C altogether, and substitute lib/util/gv_find_me.c directly into the gvedit build. The patch file to do this is attached below.

patch-cmd-gvedit-Makefile.in.diff.txt (2.3 KB)

Just to note, I’ve created a separate topic for that problem: How to run gvedit?

1 Like

@smattr It is fair to say that Graphviz does not currently support a stand-alone build of gvedit with Autotools. I don’t know about Cmake; I did not try it.

If you want to add this for Autotools, then my patch above is hackish, therefore not appropriate for general distribution. I suggest either reconfiguring libutil_C as a permanent library, or else build a temporary copy of libutil_C inside the gvedit stand-alone build.

If you make it a permanent library, you should probably decorate the official name, as ā€œlibutil_Cā€ is IMO too generic and collision-prone for general use.

My patch is sufficiently healthy for MacPorts, for the time being. I marked that as the solution (at least for MacPorts). Please consider this issue to be resolved.

Ah I see. Your patch is a modification to an existing Macports patch.

I guess this works. But I’m still puzzled what the motivation for this is. Why not adjust the patch to leave the libutil_C dependency in place, which would hopefully then result in its being built prior to gvedit? Surely this would be less fragile going forwards.

@smattr Yes that would be more robust than my link-to-source trick. However, as I mentioned earlier, MacPorts is treating libutil_C.a as a temporary file, and discarding it between major build stages. It might be possible to change this behavior, but currently I do not know how to do that. I will inquire with the MacPorts team, to see if this can be done.

However, I would prefer something else. Can the gvedit Autotools build be adjusted, such that libutil_C.a is rebuilt locally if it is missing?

In essence, I am asking for stand-alone build capability for gvedit.

The usage scenario is to first build Graphviz with core features. Then add gvedit later, if or when wanted, and after certain dependencies (such as Qt) may have been solved.

This is exactly what I was suggesting. Does this not happen if you leave the libutil_C.a dependency in place? If not, I would consider this a bug in the Graphviz build system.

This is exactly what I was suggesting.

Apologies, I misinterpreted a previous question.

Does this not happen if you leave the libutil_C.a dependency in place?

No, that does not happen. I patched cmd/gvedit/Makefile.in (57.4 KB) for exactly that. Result:

make[2]: *** No rule to make target `../../lib/util/libutil_C.la', needed by `gvedit'.

Here is a highly simplified outline of my build procedure, which mirrors the MacPorts automatic builds. This error happens on the final make step. --with-qt is the switch that activates the gvedit build, and is a key difference between build stages 1 and 2.

cd graphviz-14.0.2
configure
make
make install

clean up between builds

cd graphviz-14.0.2
configure --with-qt
cd cmd/gvedit
make

Here are the build logs for stages 1 and 2. It is complicated, so please ask questions.
graphviz.install.1108b.test.libutil-orig-linkage.debug.log.txt (1.4 MB)
gvedit.install.1108c.test.libutil-orig-linkage.debug.log.txt (220.9 KB)

Interesting. You’re right, this isn’t a workflow we typically run.

Not being an Autotools expert, I assumed it must be possible to kick off building of a single target. But this seems genuinely not supported. Quoting from this Stack Overflow answer:

starfry: Doing that will kick off the build of file (similar to what I said in my question) but it does not build the dependencies (which may be in other subdirectories). I’m looking for a solution that can be launched at the top level which will build file and whatver it depends upon (as would happen with a top level make of the whole package).

Gilles ā€˜SO- stop being evil’: starfry There’s no generic solution for this. You have to read the toplevel makefile and figure out what makes it go into the subdirectories. It’s not uncommon for this to be a loop (for loop in a shell command) that goes into several subdirectories and where the order of the loop matters — many projects that use make recursively aren’t clean with respect to dependencies.

Comments in Autotools’ generated Makefiles seem to vaguely agree:

# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.

I guess you could tweak your script to run make -C lib/util prior to make -C cmd/gvedit. But this seems just as fragile as patching in gv_find_me.c. I don’t immediately have a better suggestion than what you’re doing already.