matplotplusplus
matplotplusplus copied to clipboard
Undefined reference in matplot.lib with Visual Studio 2017
Bug category
- [x ] bug - compilation error
- [ ] bug - compilation warning
- [ ] bug - runtime error
- [ ] bug - runtime warning
- [ ] bug - logic error
Describe the bug
int main(int argc, char **argv) {
using namespace matplot;
std::vector<double> x = linspace(0, 2 * pi);
std::vector<double> y = transform(x, [](auto x) { return sin(x); });
plot(x, y, "-o");
show();
return 0;
}
I am trying to compile this project (which works fine with MinGW) with Visual Studio 2017 and I get the following link 'unresolved symbol' errors:
80>matplot.lib(network.obj) : error LNK2019: symbole externe non résolu "class std::vector<struct nodesoup::Point2D,class std::allocator<struct nodesoup::Point2D> > __cdecl nodesoup::fruchterman_reingold(class std::vector<class std::vector<unsigned __int64,class std::allocator<unsigned __int64> >,class std::allocator<class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > > > const &,unsigned int,unsigned int,unsigned int,double,class std::function<void __cdecl(class std::vector<struct nodesoup::Point2D,class std::allocator<struct nodesoup::Point2D> > const &,int)>)" (?fruchterman_reingold@nodesoup@@YA?AV?$vector@UPoint2D@nodesoup@@V?$allocator@UPoint2D@nodesoup@@@std@@@std@@AEBV?$vector@V?$vector@_KV?$allocator@_K@std@@@std@@V?$allocator@V?$vector@_KV?$allocator@_K@std@@@std@@@2@@3@IIINV?$function@$$A6AXAEBV?$vector@UPoint2D@nodesoup@@V?$allocator@UPoint2D@nodesoup@@@std@@@std@@H@Z@3@@Z) référencé dans la fonction "protected: void __cdecl matplot::network::process_force_layout(void)" (?process_force_layout@network@matplot@@IEAAXXZ)
80>matplot.lib(network.obj) : error LNK2019: symbole externe non résolu "class std::vector<struct nodesoup::Point2D,class std::allocator<struct nodesoup::Point2D> > __cdecl nodesoup::kamada_kawai(class std::vector<class std::vector<unsigned __int64,class std::allocator<unsigned __int64> >,class std::allocator<class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > > > const &,unsigned int,unsigned int,double,double)" (?kamada_kawai@nodesoup@@YA?AV?$vector@UPoint2D@nodesoup@@V?$allocator@UPoint2D@nodesoup@@@std@@@std@@AEBV?$vector@V?$vector@_KV?$allocator@_K@std@@@std@@V?$allocator@V?$vector@_KV?$allocator@_K@std@@@std@@@2@@3@IINN@Z) référencé dans la fonction "protected: void __cdecl matplot::network::process_kawai_layout(void)" (?process_kawai_layout@network@matplot@@IEAAXXZ)
80>matplot.lib(network.obj) : error LNK2019: symbole externe non résolu "class std::vector<double,class std::allocator<double> > __cdecl nodesoup::size_radiuses(class std::vector<class std::vector<unsigned __int64,class std::allocator<unsigned __int64> >,class std::allocator<class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > > > const &,double,double)" (?size_radiuses@nodesoup@@YA?AV?$vector@NV?$allocator@N@std@@@std@@AEBV?$vector@V?$vector@_KV?$allocator@_K@std@@@std@@V?$allocator@V?$vector@_KV?$allocator@_K@std@@@std@@@2@@3@NN@Z) référencé dans la fonction "protected: void __cdecl matplot::network::process_force_layout(void)" (?process_force_layout@network@matplot@@IEAAXXZ)
80>D:\Dev\compil\EyeDee-vs\bin\RelWithDebInfo\ETSimple.exe : fatal error LNK1120: 3 externes non résolus
Steps to Reproduce
find_library(my_matplot matplot HINTS ${possible_lib_paths} NO_DEFAULT_PATH) # correctly found
target_link_libraries(my_target PUBLIC my_matplot )
which lead to the above errors.
Alternatively, this does not work either during linking:
find_package(Matplot++) # correctly found
target_link_libraries(my_target PUBLIC matplot )
will complain during linking that it can't find matplot.lib, I am not sure why...:
80>LINK : fatal error LNK1104: impossible d'ouvrir le fichier 'matplot.lib' # visual output
x86_64-w64-mingw32/bin/ld.exe: cannot find -lmatplot # mingw output
Platform
- [ ] cross-platform issue - linux
- [ x] cross-platform issue - windows
- [ ] cross-platform issue - macos
Environment Details:
- OS: Windows 10
- OS Version:
- Compiler: Visual Studio 2017 win64
- Compiler version:
Additional context
When installing (shared_lib=ON), matplot.lib was copied to the install path, but not nodesoup.lib.
Copying it from source\3rd_party\Release
did not solve the problem.
I circumvented the problem, by adding nodesoup.lib to the install path, and adding it to the cmake links:
find_library(my_matplot matplot HINTS ${possible_lib_paths} NO_DEFAULT_PATH) # correctly found
target_link_libraries(my_target PUBLIC my_matplot )
find_library(my_nodesoup matplot HINTS ${possible_lib_paths} NO_DEFAULT_PATH) # correctly found
target_link_libraries(my_target PUBLIC my_nodesoup)
This compile and links well. Running the program display the graph properly (with GNUTERM=wxt). Thanks again, maybe there are some things to be done concerning the installation, and to find_package()...
Hi @PJ127, thanks for the feedback. In what directory was the library installed?
@lacc97, maybe you understand this issue better than I do. I @PJ127 installed the library with shared_lib=ON. I guess matplot is using nodesoup as a private dependency and then when we export matplot only to Matplot++Targets, it installs something that has no way of accessing nodesoup. Is that right? Maybe we could force nodesoup to be static? Or just include it in Matplot++Targets?
It's odd. You shouldn't need nodesoup or cimg if you are using the shared lib.
Also, it should be
target_link_libraries(my_target PUBLIC Matplot++::matplot)
Maybe we could force nodesoup to be static?
Nodesoup is always built as a static lib and then it gets consumed when building the shared library version of matplot.
@lacc97 That's true. Nodesoup is built with
add_library(nodesoup STATIC
${CMAKE_CURRENT_SOURCE_DIR}/nodesoup/src/algebra.cpp
It should always be static. Unless BUILD_SHARED_LIBS
is overriding this option. But I don't think that makes sense at all.
I have no idea why @PJ127 would need to find_library(my_nodesoup)
separately.
Thank you for your answers.
target_link_libraries(my_target PUBLIC Matplot++::matplot)
returns something like:
/wd4305 no such file or directory
I had to comment line 59 in lib\cmake\Matplot++\Matplot++Targets.cmake
# INTERFACE_COMPILE_OPTIONS "/wd4305;/utf-8"
but it now returns:
undefined reference to `matplot::gca()'
...
as if it did not find the matplot library. Strange, maybe I did something wrong.
It's odd. If CMake can't find the required library file (the actual .lib file) it's supposed to complain about it at configure time.
Can you maybe try again with a clean build directory?
Okay, I'll try when I have my Windows machine back in a few days.
I included an integration test/example in test/integration
.
I also extended the build workflow to always test this build script: https://github.com/alandefreitas/matplotplusplus/blob/903d1aa7883e94040c0ed3a64a415030c262f082/.github/workflows/build.yml#L87
@lacc97, I hope that's helpful somehow.
Although that's not the problem @PJ127 is having, it seems like matplot++-config.cmake
is not going to the default directory on windows, though:
https://github.com/alandefreitas/matplotplusplus/runs/1212059007?check_suite_focus=true#step:7:59
https://github.com/alandefreitas/matplotplusplus/runs/1212059007?check_suite_focus=true#step:8:32
I don't know if this should really be going to another directory by default. CMake recommends C:/Program Files (x86)/
for installing but it doesn't look for matplot++-config.cmake
there.
I had this same issue when I downloaded the pre-built binary package (https://github.com/alandefreitas/matplotplusplus/releases), installed it, and tried to build with Visual Studio 2019. In the binary distribution after installation, the matplot.lib
object library is in the main lib
directory, but the nodesoup.lib
object library is in the Matplot++
subdirectory. To work around these linker errors, I had to:
-
Add
nodesoup.lib
as an explicit dependency (either with#pragma comment(lib, "nodesoup.lib")
in the source or by addingnodesoup.lib
to the "Linker → Input → Additional Dependencies" in the Visual Studio project properties). -
Add the
lib/Matplot++
subdirectory to the linker's search path (Linker → General → Additional Library Directories).
Clearly, the way that the matplot.lib
object library is being built on Windows is not merging the contents of nodesoup.lib
into it, nor does it even include a reference to it in a relative path (i.e., Matplot++/nodesoup.lib
). That is fairly normal; adding a "reference" from one project to another in Visual Studio only sets up a build dependency, it doesn't perform any sort of linking.
You can ensure that the two object libraries are merged into a single one by running a command like the following as a post-build event:
lib.exe /out:matplot_complete.lib matplot.lib nodesoup.lib
(If you're more familiar with the Gnu/*nix toolchain, this would be the moral equivalent of ar
.)
Alternatively, starting with Visual Studio 2015 Update 2, you can use the /wholearchive
switch when building: https://docs.microsoft.com/en-us/cpp/build/reference/wholearchive-include-all-library-object-files
I'm not sure if there's a better way of doing this with CMake; I haven't had the pleasure of using that tool yet.
Hi
I have a similar issue as I run a script (line.cpp) on my ubuntu20 machine with matplot++ installed.
#include <cmath>
#include <matplot/matplot.h>
int main() {
using namespace matplot;
std::vector<double> x = linspace(0, 2 * pi);
std::vector<double> y1 = transform(x, [](auto x) { return sin(x); });
std::vector<double> y2 = transform(x, [](auto x) { return sin(x - 0.25); });
std::vector<double> y3 = transform(x, [](auto x) { return sin(x - 0.5); });
plot(x, y1, "g", x, y2, "b--o", x, y3, "c*");
show();
return 0;
}
with command:
g++ -std=c++17 line.cpp -o line.o
Eventually, it shows
/usr/bin/ld: /tmp/ccDNNI2Q.o: in function `main':
line.cpp:(.text+0x34): undefined reference to `matplot::linspace(double, double)'
collect2: error: ld returned 1 exit status
Do you have a solution to that?
Thanks in advance
@yu-ting-py That is a different problem than what is described here, with a much simpler solution. You need to link to the MatPlot++ library. Pass the option -l:matplot.lib
when you run the g++
command. (You may also need to specify the path to where the linker can find the .lib
file with the -L
option.)
You may struggle to get all the dependencies linked in unless you have a thorough understanding of the C++ build toolchain. The instructions in the repository assume you're using CMake to build MatPlot++, which is what I would recommend doing unless you have a specific reason not to use it.
I have installed MatPlot++ with CMake according to the readme file. Do I need to use CMake instead of g++
command every time I plot something?