Compiling Tests Fails: "Undefined symbols for architecture x86_64"

What I’m doing
I am using MacOS, and trying to run a test the igraph_edge_betweeness.c test on the develop branch of C igraph, using the command mentioned in this comment:
https://github.com/igraph/igraph/issues/1851#issuecomment-974604878

I’ve already followed all the steps in the c installation guide, and have the igraph library fully installed. I have also been able to successfully compile and run the example program in the tutorial. My problem occurs when I try to compile the test code.

What’s happening
After removing some -L directories and libraries that I don’t have locally, I’m left with the following command.

gcc igraph_edge_betweenness.c ../../src/centrality/betweenness.c -I ../../src/ -I ../../include/ -I ../../build/include -I ../../build/src/ -ligraph -Wall -Wextra -g

However, when I run it, I get a linker error.

Undefined symbols for architecture x86_64:
  "_daxpy_", referenced from:
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdsapps_ in libigraph.a(dsapps.c.o)
  "_dcopy_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
      _igraphdnaup2_ in libigraph.a(dnaup2.c.o)
      _igraphdsaup2_ in libigraph.a(dsaup2.c.o)
      _igraphdgetv0_ in libigraph.a(dgetv0.c.o)
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      ...
  "_ddot_", referenced from:
      _igraphdnaup2_ in libigraph.a(dnaup2.c.o)
      _igraphdsaup2_ in libigraph.a(dsaup2.c.o)
      _igraphdgetv0_ in libigraph.a(dgetv0.c.o)
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdsaitr_ in libigraph.a(dsaitr.c.o)
  "_dgemv_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdgetv0_ in libigraph.a(dgetv0.c.o)
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdneigh_ in libigraph.a(dneigh.c.o)
      _igraphdsaitr_ in libigraph.a(dsaitr.c.o)
      _igraphdsapps_ in libigraph.a(dsapps.c.o)
      ...
  "_dgeqr2_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
  "_dger_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
  "_dlabad_", referenced from:
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdlaqrb_ in libigraph.a(dlaqrb.c.o)
  "_dlacpy_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdneigh_ in libigraph.a(dneigh.c.o)
      _igraphdsapps_ in libigraph.a(dsapps.c.o)
  "_dlaev2_", referenced from:
      _igraphdstqrb_ in libigraph.a(dstqrb.c.o)
  "_dlahqr_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
  "_dlamch_", referenced from:
      _igraphdnaupd_ in libigraph.a(dnaupd.c.o)
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdsaupd_ in libigraph.a(dsaupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
      _igraphdnaup2_ in libigraph.a(dnaup2.c.o)
      _igraphdsaup2_ in libigraph.a(dsaup2.c.o)
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      ...
  "_dlanhs_", referenced from:
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdlaqrb_ in libigraph.a(dlaqrb.c.o)
  "_dlanst_", referenced from:
      _igraphdstqrb_ in libigraph.a(dstqrb.c.o)
  "_dlanv2_", referenced from:
      _igraphdlaqrb_ in libigraph.a(dlaqrb.c.o)
  "_dlapy2_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdsortc_ in libigraph.a(dsortc.c.o)
      _igraphdnaup2_ in libigraph.a(dnaup2.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdnconv_ in libigraph.a(dnconv.c.o)
      _igraphdneigh_ in libigraph.a(dneigh.c.o)
      _igraphdstqrb_ in libigraph.a(dstqrb.c.o)
      ...
  "_dlarf_", referenced from:
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
  "_dlarfg_", referenced from:
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdlaqrb_ in libigraph.a(dlaqrb.c.o)
  "_dlarnv_", referenced from:
      _igraphdgetv0_ in libigraph.a(dgetv0.c.o)
  "_dlartg_", referenced from:
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdsapps_ in libigraph.a(dsapps.c.o)
      _igraphdstqrb_ in libigraph.a(dstqrb.c.o)
  "_dlascl_", referenced from:
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdsaitr_ in libigraph.a(dsaitr.c.o)
      _igraphdstqrb_ in libigraph.a(dstqrb.c.o)
  "_dlaset_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdsapps_ in libigraph.a(dsapps.c.o)
  "_dlasr_", referenced from:
      _igraphdstqrb_ in libigraph.a(dstqrb.c.o)
  "_dnrm2_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
      _igraphdnaup2_ in libigraph.a(dnaup2.c.o)
      _igraphdsaup2_ in libigraph.a(dsaup2.c.o)
      _igraphdgetv0_ in libigraph.a(dgetv0.c.o)
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdneigh_ in libigraph.a(dneigh.c.o)
      ...
  "_dorm2r_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
  "_drot_", referenced from:
      _igraphdlaqrb_ in libigraph.a(dlaqrb.c.o)
  "_dscal_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
      _igraphdnaitr_ in libigraph.a(dnaitr.c.o)
      _igraphdnapps_ in libigraph.a(dnapps.c.o)
      _igraphdneigh_ in libigraph.a(dneigh.c.o)
      _igraphdsaitr_ in libigraph.a(dsaitr.c.o)
      _igraphdsapps_ in libigraph.a(dsapps.c.o)
      ...
  "_dsteqr_", referenced from:
      _igraphdseupd_ in libigraph.a(dseupd.c.o)
  "_dswap_", referenced from:
      _igraphdsaup2_ in libigraph.a(dsaup2.c.o)
      _igraphdsesrt_ in libigraph.a(dsesrt.c.o)
      _igraphdsgets_ in libigraph.a(dsgets.c.o)
  "_dtrevc_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
      _igraphdneigh_ in libigraph.a(dneigh.c.o)
  "_dtrmm_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
  "_dtrsen_", referenced from:
      _igraphdneupd_ in libigraph.a(dneupd.c.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

What I’ve tried
A quick google search of “daxpy”, “dcopy”, etc. tells me that these are functions from the Lapack package. This is strange to me, as Lapack is available by default for MacOS, and even if not, it is listed as one of the packages that igraph bundles.

I’ve tried a number of different things to get this to work. (I’m new to this, so excuse me if some of these attempts are nonsensical)

  1. Tried including lapack explictly (-llapack). This gave the exact same error.
gcc igraph_edge_betweenness.c ../../src/centrality/betweenness.c -I ../../src/ -I ../../include/ -I ../../build/include -I ../../build/src/ -llapack -ligraph -Wall -Wextra -g
  1. Installed lapack separately via homebrew, and then added the include and library directories directly into gcc. Still same error.
gcc igraph_edge_betweenness.c ../../src/centrality/betweenness.c -I ../../src/ -I ../../include/ -I ../../build/include -I ../../build/src/ -I /usr/local/Cellar/lapack/3.10.0/include -L /usr/local/Cellar/lapack/3.10.0/lib -llapack -ligraph -Wall -Wextra -g

Other notes
Something I’ve noticed is that if I remove the line #include "test_utilities.inc" from igraph_edge_betweeness.c, as well as all references to print_vector and VERIFY_FINALLY_STACK, then once again the code is able to compile and run.

You are not linking to all required libraries. What’s required depends on your system, as well as on how you compiled igraph.

Actually, I do not suggest that you run tests this way. If you want to build test xx, then simply use make test_xx (or ninja test_xx if you’re using ninja instead of make—highly recommended). To run it, run tests/test_xx from your build directory.

To build all tests, use the target build_tests. To build and run all tests, use the target check.


In summary, let CMake figure out how to link things, at least until you become more comfortable. If you want to compile your own program, which is not part of the test suite, install igraph to a prefix of your choosing, and still let CMake do the work for you. If you really want to provide all the linking options manually, you can check what’s required by looking at the igraph.pc file or using pkgconfig (again, see the tutorial I linked).

If you are implementing a new igraph function, just make your test program be part of the test suite, then you can run it as any other test without needing to install igraph and set of a separate CMake project just for your test program. This is what I normally do.

1 Like

Note: On macOS you can link to BLAS/LAPACK by adding -framework Accelerate to your linking command. As I recall, this won’t show up in igraph.pc, but this is the simple way to do it. This again illustrates why I strongly recommend that you leave the complexities of linking to CMake.

1 Like

Worked like a charm. Thanks!

Let us know if there are additional questions. You should not be spending too much time on these arcane technical details—so just ask when you think that we can give an answer immediately.

Perhaps in addition to what @szhorvat wrote, you can also invoke cmake and ctest directly, so it won’t depend on whether you are using make or ninja as a build system. To compile a specific test, use
cmake --build . --target text_xxx. To run a specific test, including comparison to a possible .out file, you can use ctest -R test_xxx. Here, the -R flag accepts regular expressions, so you can also run all examples using ctest -R example_.* or all community related tests using ctest -R community, et cetera. If you simply want to run all tests, you can simply invoke ctest.