4 Replies Latest reply on Jun 15, 2014 11:54 AM by nnunn@ausport.gov.au

    Linking against ACML problem on Windows




      I'd like to use ACML to speed up my code which uses Armadillo.


      Without ACML, everything works fine, both on Linux (ArchLinux x86_64, gcc 4.8.1) and Windows (64 bits, Visual Studio 2012 Update 3). I develop inside Qt Creator and generate a makefile using qmake. Armadillo is directly included in my project and as such does not require special treatment for compilation or linking  (as it is simply a template library).


      I want now to use ACML. I downloaded ACML 5.3.1 on both linux (which I compiled part using gfortran) and acml5.3.1-ifort64.exe for Windows. An important question here: do I need a fortran compiler on Windows for ACML if all I'm doing is developing in C/C++?


      I then try to enable ACML inside Armadillo (in config.hpp, Armadillo's configuration header) and add the required link flags for ACML. On Linux, no problem, it links fine (as reported by 'ldd'):

      $ ldd project


              libacml_mp.so => /usr/lib/acml/gfortran/libacml_mp.so (0x00007f420e588000)



      On Windows though, I cannot link correctly. I don't mind linking either statically or dynamically. This project will might be shipped in a proprietary application, so I would like to be as close as possible to the Redistribution Agreements.The later specifies that I cannot distribute, publish or sublicense the Documentation, the Sample Source, the Libraries (except when built into the Distributed Software). So is it required to link statically then?


      In any case, linking to a library is done through qmake's LIBS variable:

      unix: {

          INCLUDEPATH += /usr/include/acml/gfortran/

          LIBS += -L/usr/lib/acml/gfortran/ -lacml_mp


      win32: {

          ACMLDIR = $$quote(C:\AMD\acml5.3.1\ifort64_mp)

          INCLUDEPATH += $$quote($$ACMLDIR\include)

          #LIBS += -L$$quote($$ACMLDIR\lib) -lacml_mp

          LIBS += $$quote(C:\AMD\acml5.3.1\ifort64_mp\lib\libacml_mp_dll.lib)


      But it always fails to link:

      tf.obj:-1: error: LNK2019: unresolved external symbol sgetrf_ referenced in function "void __cdecl arma::lapack::getrf<double>(int *,int *,double *,int *,int *,int *)" (??$getrf@N@lapack@arma@@YAXPEAH0PEAN000@Z)


      Grepping for "sgetrf_" reveals that libacml_mp.lib contains that symbol but even adding "$$quote(C:\AMD\acml5.3.1\ifort64_mp\lib\libacml_mp.lib)" to the LIBS variable gives the same LNK2019 error.


      The unresolved symbol is a lapack function (or function wrapper?) so if I understand correctly, the linker is not finding the right symbol in ACML library. Normally I would check that the linking flags are ok, but they seem to be!


      All in all, my questions are:

      1) Do I need a fortran compiler on Windows for ACML if all I'm doing is developing in C/C++?

      2) Should I link statically or dynamically?

      3) How to link correctly?


      Thanks a lot for any hints!!

        • Re: Linking against ACML problem on Windows

          I am able to build the C examples without needing a Fortran compiler.

          For instance from a DOS command prompt (with Cygwin in the path), I can run "make cgels_c_example.res" and the example builds and runs.


          This example demonstrates one way the dll libraries can be linked.  It does use libacml_mp_dll.lib,   and uses cl to do the actual link.  The example uses the -MD programming model.  We do include -MT libraries for ifort as well.


          Unfortunately, static linking does require the associated compiler, because the compiler license does not allow redistribution of the static runtime libraries.

          • Re: Linking against ACML problem on Windows

            Notice all those int* args:  "arma::lapack::getrf<double>(int *,int *,double *,int *,int *,int *);"


            I had similar problem using ACML for gmsh (VC2010).  Solution was to make simple wrappers to change certain LAPACK pointers to ACML references:


            // LAPACK:

            void dgetrf_(int *M, int *N, double *A, int *lda, int *ipiv, int *info)
              // ACML v4.4
              dgetrf(*M, *N, A, *lda, ipiv, info);


            // LAPACK:

            void dgetrs_(char *trans, int *N, int *nrhs, double *A, int *lda, int *ipiv, double *b, int *ldb, int *info)
              // ACML v4.4
              dgetrs(trans[0], *N, *nrhs, A, *lda, ipiv, b, *ldb, info);


            Also had to sprinkle in a few extern "C" {...}

            Good luck!