Archived OpenModelica forums. Posting is disabled.

Alternative forums include GitHub discussions or StackOverflow (make sure to read the Stack Overflow rules; you need to have well-formed questions)


Forgot password? | Forgot username? | Register

Linker error when using OMEdit export FMU funcitonality

Linker error when using OMEdit export FMU funcitonality

Hi

Problem description summary:

I have developed Model which includes a function that makes an extern C call. I supply a shared library (linux *.so file) which are linked to during compilation using OMEdit. I can verify that I can simulate my model. My problem comes when I try to export my model as a FMU unit. It seems the linker cannot resolve / find my shared library when trying to export the simulation to a FMU unit.

Problem description details:

I have formulated an optimal control problem (MPC formulation) in CPP using Casadi (solved with Ipopt) (libcassadi.so is a CPP shared library). In addition, I have created an extern "C" solve function which is a C API to pass arguments to the MPC formulation, and return the optimal control solution.

My mpc.cpp function are defined as:

Code:


#include <casadi/casadi.hpp>
using namespace casadi;

extern "C" double solve( double x1, double x2, double x3 )
{
    // Symbols/expressions
    MX x = MX::sym("x");
    MX y = MX::sym("y");
    MX z = MX::sym("z");
    MX f = pow(x,2)+100*pow(z,2);
    MX g = z+pow(1-x,2)-y;

    MXDict nlp;                 // NLP declaration
    nlp["x"]= vertcat(x,y,z);   // decision vars
    nlp["f"] = f;               // objective
    nlp["g"] = g;               // constraints

    // Create solver instance
    Function F = nlpsol("F","ipopt",nlp);

    // Solve the problem using a guess
    F(DMDict{{"x0",DM({2.5,3.0,0.75})},{"ubg",0},{"lbg",0}});

    return rand()/RAND_MAX;
}

To compile the latter, I use CMake

Code:


cmake_minimum_required (VERSION 2.6)

project (01_mpc_cstr)

SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -fPIC")

set ( SRC_DIR ./src/ )

set ( MPC_SRCS ${SRC_DIR}mpc.cpp)

add_library(nmpc MODULE ${MPC_SRCS})

find_library( CASADI_LIB libcasadi.so )

if ( CASADI_LIB )
    message( STATUS "Found library: ${CASADI_LIB}" ...)
    target_link_libraries (nmpc ${CASADI_LIB})
else ()
    message( WARNING "Cannot find library: ${CASADI_LIB}" ...)
endif ()


find_library( STDCXX_LIB libstdc++.so.6 )

if ( STDCXX_LIB )
    message( STATUS "Found library: ${STDCXX_LIB}" ...)
    target_link_libraries (nmpc ${STDCXX_LIB})
else ()
    message( WARNING "Cannot find library: ${STDCXX_LIB}" ...)
endif ()

Next, I use OMEdit to construct my model class and define a function with an external C function call.

Code:


model MPC

  function solve       
    input Real x1, x2 ,x3;
    output Real u;
  external "C" u = solve(x1, x2 ,x3);
    annotation(Library="nmpc", LibraryDirectory="modelica://MPC/Resources/Library")
  end solve;

  Modelica.Blocks.Interfaces.RealInput x1 annotation( ...
  Modelica.Blocks.Interfaces.RealInput x2 annotation( ...
  Modelica.Blocks.Interfaces.RealInput x3 annotation( ...
  Modelica.Blocks.Interfaces.RealOutput u annotation( ...

algorithm

  u := solve(x1, x2, x3);
[color=#ff0000]
end MPC;

Now, using OMEdit, I can successfully compile and simulate the former model.

However, when I want to export the Model to a FMU unit, then I get the following linker error:

Code:


gcc -shared -o MPC.so MPC.o MPC_functions.o MPC_records.o MPC_01exo.o MPC_02nls.o MPC_03lsy.o MPC_04set.o MPC_05evt.o MPC_06inz.o MPC_07dly.o MPC_08bnd.o MPC_09alg.o MPC_10asr.o MPC_11mix.o MPC_12jac.o MPC_13opt.o MPC_14lnz.o MPC_15syn.o MPC_16dae.o MPC_17inl.o MPC_init_fmu.o MPC_FMU.o  -L"/home/johannes/01_cstr_introduction/models/MPC"  -Wl,-Bstatic "-L/usr/bin/../lib/x86_64-linux-gnu/omc" -Wl,-rpath="/usr/bin/../lib/x86_64-linux-gnu/omc" "-L/usr/bin/../lib/" -Wl,-rpath="/usr/bin/../lib/" "-L/home/johannes/.openmodelica/binaries/MPC" -Wl,-rpath="/home/johannes/.openmodelica/binaries/MPC" "-L/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/x86_64-linux" -Wl,-rpath="/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/x86_64-linux" "-L/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/linux64" -Wl,-rpath="/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/linux64" "-L/home/johannes/01_cstr_introduction/models/MPC/Resources/Library" -Wl,-rpath="/home/johannes/01_cstr_introduction/models/MPC/Resources/Library" -lnmpc -Wl,-Bdynamic -L'/usr/bin/../lib/x86_64-linux-gnu/omc' -Wl,-rpath,'/usr/bin/../lib/x86_64-linux-gnu/omc'   -lSimulationRuntimeFMI  -Wl,--no-as-needed -Wl,--disable-new-dtags -llapack -lblas -lm -lm -lpthread -rdynamic -Wl,--no-undefined
/usr/bin/ld: cannot find -lnmpc
collect2: error: ld returned 1 exit status

How does the internal export to FMU work?

Any ideas in how to resolve this will be appreciated!



Re: Linker error when using OMEdit export FMU funcitonality

What do you have set in the FMU export setting in OMEdit in Tools->Options->FMI: "Platforms"?
Is it static? Is it dynamic?

Note that if you have an .so which is used in the FMU you will need to copy that one manually inside the generated FMU.
Can you compile this library as a static library .a?

As far as I can see from these paths below it should find the "nmpc" library.

Code:


-Wl,-Bstatic
"-L/usr/bin/../lib/x86_64-linux-gnu/omc" -Wl,-rpath="/usr/bin/../lib/x86_64-linux-gnu/omc" "-L/usr/bin/../lib/"
-Wl,-rpath="/usr/bin/../lib/" "-L/home/johannes/.openmodelica/binaries/MPC" -Wl,-rpath="/home/johannes/.openmodelica/binaries/MPC"
"-L/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/x86_64-linux"
-Wl,-rpath="/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/x86_64-linux"
"-L/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/linux64"
-Wl,-rpath="/home/johannes/01_cstr_introduction/models/MPC/Resources/Library/linux64" "
-L/home/johannes/01_cstr_introduction/models/MPC/Resources/Library"
-Wl,-rpath="/home/johannes/01_cstr_introduction/models/MPC/Resources/Library"
-lnmpc
-Wl,-Bdynamic

Probably it does find it, but because we force a static link for it via -Wl,-Bstatic it doesn't use it.

To fix this i suggest you try to make a static library as otherwise you will nee to copy *ALL* the dependent dlls (.so) inside the generated FMU.
If you don't do that and sen the FMU to somebody they will not be able to use it if they don't have the same .so installed.

Re: Linker error when using OMEdit export FMU funcitonality

Hi

I have tried several of your suggestions with the following observations:

Building static libraries:

1. If I build a static library libnmpc.a, then using applying Export->FMU results in -lnmpc detected. However, the subsequent problem I experience is that the dependent libraries libcasadi.so and libstdc++.so.6 are not found.

2. For the simulation environment, I can pass the latter in Simulation setup -> Compiler Flags = -lcasadi -lstdc++, which enables me to simulate.

NOTE: I have Tools->Options->FMI: "Platforms = static.

Building shared libraries:

1. Building a shared library libnmpc.so enables simulating my model without the need to pass Simulation setup -> Compiler Flags = -lcasadi -lstdc++.

2. Again, I sit with the problem of not detecting lnmpc when I Export->FMU. Setting I have Tools->Options->FMI: "Platforms = dynamic. does not change -Wl,-Bstatic to -Wl,-Bdynamic, nor does it effect the net outcome (not sure if it should).

Using both static and shared libraries:

1. Again for this scenario, I pick up -lnmp, but cannot detect -lcasadi.

Some conclusions:

I still contemplate how to append the dynamic library dependencies libcasadi.so and libstdc++.so.6 to my static library target being libnmpc.a. I am of opinion this should be done by setting some property configured in the CMakelists.txt file. I have tried:

Code:


target_link_libraries (nmpc ${CASADI_LIB})
target_link_libraries (nmpc ${STDCXX_LIB})

but this does not resolve it.

Still open questions:

1. How do one link / bind share libraries (in this example libcasadi.so and libstdc++.so.6) with a static generated library?

Re: Linker error when using OMEdit export FMU funcitonality

One probable solution (hacked and not portable):

1. Build a shared library of interest being libnmpc.so in this case.
2. Export->FMU which will prompt the usual error of

Code:

/usr/bin/ld: cannot find -lnmpc

3. Go to the generated folder where the FMU export attempt was made. Typically in your work directory

Code:

/home/>USER>/OMEdit

,
4. Enter folder

Code:

/OMEdit/components.mpc/components_mpc.fmutmp/sources

5. ./configure which will prompt on the first try

Code:

configure: error: FMI headers need to be present in the include path. 

To solve this export your path where this FMI headers are located, i.e.,

Code:

CPPFLAGS=-I/usr/include/omc/c/fmi/

6. ./configure && make.

7. Make will fail because -Wl,-Bstatic has also been defined for -lnmp and we only have libnmpc.so which depends on libcasadi.so. To resolve this, modify the compiler arguments to include -Wl,-Bdynamic -L<path to nmpc lib> -lnmpc.

8. make which results in a FMU which can be simulated.

Open questions:

1. One needs to created a static link such that the FMU unit is portable. Does this imply I need to compile Casadi as a static library also?
2. Should one add dynamic linking arguments to Casadi and then have a portable FMU that requires Casadi installed on other systems?

Edited by: phillipmaree - Apr-23-20 07:29:00

Re: Linker error when using OMEdit export FMU funcitonality

The best solution would be to compile *all* the FMU dependencies as static libraries (if possible).
If is not possible, you can ask the people you send the FMU to to install the dependencies.

You should try to get rid of as many dependencies as possible, to get rid of libstdc++ use g++ to link and flags "-static-libstdc++".

As to the fact that platform dynamic does not change  -Wl,-Bstatic part to  -Wl,-Bdynamic this seems to be a bug. I will open a ticket about it.

For now I think you can just:

Code:


export MODELICAUSERCFLAGS=-Wl,-Bdynamic -lnmpc

before running OMEdit or omc to build the FMU (or add it to compiler flags in OMEdit).

You could also, after building the FMU, unzip it, use "ldd -r" on the generated .so file and then copy all the dependencies in the directory where the generated libnpmc.so is, the repack the zip into an FMU again. This way it should work to send it to somebody BUT it highly depends on how the FMI tool loads the FMU and what is the search path for the dependent .so files, some might add the path where the FMU is unpacked to the search others might not. For example see how windows loads dlls if the LOAD_WITH_ALTERED_SEARCH_PATH is given.

There are 0 guests and 0 other users also viewing this topic
You are here: