error LNK2019, 3 unresolved external symbols

14 views (last 30 days)
Hi, I'm new to Matlab. I'm trying to build a C mex file. The C file and header files are all on the search path. I've been able to build C mex files, following the documents, but I'm not sure what's wrong here. Here's the error message I'm getting:
Error using mex Creating library DynamicProgrammingQ2.lib and object DynamicProgrammingQ2.exp DynamicProgrammingQ2.obj : error LNK2019: unresolved external symbol dp_costs referenced in function mexFunction DynamicProgrammingQ2.obj : error LNK2019: unresolved external symbol dp_build_gamma referenced in function mexFunction DynamicProgrammingQ2.obj : error LNK2019: unresolved external symbol dp_all_indexes referenced in function mexFunction DynamicProgrammingQ2.mexw64 : fatal error LNK1120: 3 unresolved externals
Please point me in the right direction.
  2 Comments
Geoff Hayes
Geoff Hayes on 14 Jan 2015
Matthew - it sounds like your C code is referencing functions, for example dp_build_gamma (and a couple of others too), that you probably have defined in a header but you don't have the body for them. Could it be that there is a library that you should be linking into your build? Also, what is the mex command that you are using to build with?
Matthew
Matthew on 14 Jan 2015
I'm using command:
mex 'T:\Matlab\SRVF_FDA\DynamicProgrammingQ2.c'
And here's the C code:
#include "mex.h"
#include <math.h>
#include "dp_grid.h"
/* Signature:
* function [G T] = dp_mex( Q1, T1, Q2, T2, tv1, tv2 )
* Arguments are checked in dp.m, not here. */
void mexFunction(int nlhs, mxArray *plhs[ ],int nrhs, const mxArray *prhs[ ]){
double *Q1 = 0;
double *T1 = 0;
double *Q2 = 0;
double *T2 = 0;
double *lam1 = 0;
double lam;
int nsamps1;
int nsamps2;
double *tv1 = 0;
double *tv2 = 0;
int *idxv1 = 0;
int *idxv2 = 0;
int ntv1;
int ntv2;
double *G = 0;
double *T = 0;
int Gsize;
int dim = 0;
double *E = 0; /* E[ntv1*j+i] = cost of best path to (tv1[i],tv2[j]) */
int *P = 0; /* P[ntv1*j+i] = predecessor of (tv1[i],tv2[j]) along best path */
double m, rootm;
int sr, sc; /* source row and column index */
int tr, tc; /* target row and column index */
int Galloc_size;
double *pres;
/* [G T dist] = dp_mex( Q1, T1, Q2, T2, tv1, tv2 ); */
Q1 = mxGetPr( prhs[0] );
T1 = mxGetPr( prhs[1] );
Q2 = mxGetPr( prhs[2] );
T2 = mxGetPr( prhs[3] );
tv1 = mxGetPr( prhs[4] );
tv2 = mxGetPr( prhs[5] );
lam1 = mxGetPr( prhs[6] );
lam = *lam1;
dim = mxGetM( prhs[0] );
nsamps1 = mxGetN( prhs[1] ); /* = columns(T1) = columns(Q1)+1 */
nsamps2 = mxGetN( prhs[3] ); /* = columns(T2) = columns(Q2)+1 */
ntv1 = mxGetN( prhs[4] );
ntv2 = mxGetN( prhs[5] );
Galloc_size = ntv1>ntv2 ? ntv1 : ntv2;
if ( !(idxv1=(int*)mxMalloc(ntv1*sizeof(int))) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "failed to allocate idxv1" );
goto cleanup;
}
if ( !(idxv2=(int*)mxMalloc(ntv2*sizeof(int))) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "failed to allocate idxv2" );
goto cleanup;
}
if ( !(E=(double*)mxMalloc(ntv1*ntv2*sizeof(double))) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "failed to allocate E" );
goto cleanup;
}
if ( !(P=(int*)mxCalloc(ntv1*ntv2,sizeof(int))) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "failed to allocate P" );
goto cleanup;
}
if ( !(plhs[0]=mxCreateDoubleMatrix(1,Galloc_size,mxREAL)) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "mxCreateDoubleMatrix failed" );
goto cleanup;
}
if ( !(plhs[1]=mxCreateDoubleMatrix(1,Galloc_size,mxREAL)) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "mxCreateDoubleMatrix failed" );
goto cleanup;
}
if ( !(plhs[2]=mxCreateDoubleScalar(0.0)) )
{
mexErrMsgIdAndTxt( "dp:AllocFailed", "mxCreateDoubleScalar failed" );
goto cleanup;
}
G = mxGetPr( plhs[0] );
T = mxGetPr( plhs[1] );
pres = mxGetPr( plhs[2] );
/* dp_costs() needs indexes for gridpoints precomputed */
dp_all_indexes( T1, nsamps1, tv1, ntv1, idxv1 );
dp_all_indexes( T2, nsamps2, tv2, ntv2, idxv2 );
/* Compute cost of best path from (0,0) to every other grid point */
*pres = dp_costs( Q1, T1, nsamps1, Q2, T2, nsamps2,
dim, tv1, idxv1, ntv1, tv2, idxv2, ntv2, E, P, lam );
/* Reconstruct best path from (0,0) to (1,1) */
Gsize = dp_build_gamma( P, tv1, ntv1, tv2, ntv2, G, T );
mxSetN( plhs[0], Gsize );
mxSetN( plhs[1], Gsize );
cleanup:
if ( idxv1 ) mxFree( idxv1 );
if ( idxv2 ) mxFree( idxv2 );
if ( E ) mxFree( E );
if ( P ) mxFree( P );
}
The header file is in the same directory on the search path. Here it is:
#ifndef DP_GRID_H
#define DP_GRID_H 1
/**
* Computes weights of all edges in the DP matching graph,
* which is needed for the Floyd-Warshall all-pairs shortest-path
* algorithm.
*
* The matrix of edge weights E must be allocated ahead of time by
* the caller. E is an ntv1 x ntv2 x ntv1 x ntv2 matrix. If i and k
* are column indices and j and l are row indices, then the weight of the
* edge from gridpoint (tv1[i],tv2[j]) to gridpoint (tv1[k],tv2[l]) is
* stored in E(j,i,l,k) when this function returns.
* Mapping:
* (j,i,l,k) :--> j*ntv1*ntv2*ntv1 +
* i*ntv2*ntv1 +
* l*ntv1 +
* k
*
* \param Q1 values of the first SRVF
* \param T1 changepoint parameters of the first SRVF
* \param nsamps1 the length of T1
* \param Q2 values of the second SRVF
* \param T2 changepoint parameters of the second SRVF
* \param nsamps2 the length of T2
* \param dim dimension of the ambient space
* \param tv1 the Q1 (column) parameter values for the DP grid
* \param idxv1 Q1 indexes for tv1, as computed by \c dp_all_indexes()
* \param ntv1 the length of tv1
* \param tv2 the Q2 (row) parameter values for the DP grid
* \param idxv2 Q2 indexes for tv2, as computed by \c dp_all_indexes()
* \param ntv2 the length of tv2
* \param E [output] pointer to the edge weight matrix. Must already be
* allocated, with size (ntv1*ntv2)^2.
*/
void dp_all_edge_weights(
double *Q1, double *T1, int nsamps1,
double *Q2, double *T2, int nsamps2,
int dim,
double *tv1, int *idxv1, int ntv1,
double *tv2, int *idxv2, int ntv2,
double *W, double lam );
/**
* Computes cost of best path from (0,0) to all other gridpoints.
*
* \param Q1 values of the first SRVF
* \param T1 changepoint parameters of the first SRVF
* \param nsamps1 the length of T1
* \param Q2 values of the second SRVF
* \param T2 changepoint parameters of the second SRVF
* \param nsamps2 the length of T2
* \param dim dimension of the ambient space
* \param tv1 the Q1 (column) parameter values for the DP grid
* \param idxv1 Q1 indexes for tv1, as computed by \c dp_all_indexes()
* \param ntv1 the length of tv1
* \param tv2 the Q2 (row) parameter values for the DP grid
* \param idxv2 Q2 indexes for tv2, as computed by \c dp_all_indexes()
* \param ntv2 the length of tv2
* \param E [output] on return, E[ntv2*i+j] holds the cost of the best
* path from (0,0) to (tv1[i],tv2[j]) in the grid.
* \param P [output] on return, P[ntv2*i+j] holds the predecessor of
* (tv1[i],tv2[j]). If predecessor is (tv1[k],tv2[l]), then
* P[ntv2*i+j] = k*ntv2+l.
* \return E[ntv1*ntv2-1], the cost of the best path from (tv1[0],tv2[0])
* to (tv1[ntv1-1],tv2[ntv2-1]).
*/
double dp_costs(
double *Q1, double *T1, int nsamps1,
double *Q2, double *T2, int nsamps2,
int dim,
double *tv1, int *idxv1, int ntv1,
double *tv2, int *idxv2, int ntv2,
double *E, int *P, double lam );
/**
* Computes the weight of the edge from (a,c) to (b,d) in the DP grid.
*
* \param Q1 values of the first SRVF
* \param T1 changepoint parameters of the first SRVF
* \param nsamps1 the length of T1
* \param Q2 values of the second SRVF
* \param T2 changepoint parameters of the second SRVF
* \param nsamps2 the length of T2
* \param dim dimension of the ambient space
* \param a source Q1 parameter
* \param b target Q1 parameter
* \param c source Q2 parameter
* \param d target Q2 parameter
* \param aidx index such that Q1[aidx] <= a < Q1[aidx+1]
* \param cidx index such that Q2[cidx] <= c < Q2[cidx+1]
*/
double dp_edge_weight(
double *Q1, double *T1, int nsamps1,
double *Q2, double *T2, int nsamps2,
int dim,
double a, double b,
double c, double d,
int aidx, int cidx, double lam );
/**
* Given predecessor table P, builds the piecewise-linear reparametrization
* function gamma.
*
* G and T must already be allocated with size max(ntv1,ntv2). The actual
* number of points on gamma will be the return value.
*
* \param P P[ntv2*i+j] holds the predecessor of (tv1[i],tv2[j]). If
* predecessor is (tv1[k],tv2[l]), then P[ntv2*i+j] = k*ntv2+l.
* \param tv1 the Q1 (column) parameter values for the DP grid
* \param ntv1 the length of tv1
* \param tv2 the Q2 (row) parameter values for the DP grid
* \param ntv2 the length of tv2
* \param G [output] reparametrization function values
* \param T [output] reparametrization changepoint parameters
* \return the length of G (same as length of T).
*/
int dp_build_gamma(
int *P,
double *tv1, int ntv1,
double *tv2, int ntv2,
double *G, double *T );
/**
* Given t in [0,1], return the integer i such that t lies in the interval
* [T[i],T[i+1]) (or returns n-2 if t==T[n-1]).
*
* \param T an increasing sequence
* \param n the length of T
* \param t the parameter value to lookup ( T[0] <= t <= T[n-1] ).
* \return the integer i such that t lies in the interval [T[i],T[i+1])
* (or n-2 if t==T[n-1]).
*/
int dp_lookup( double *T, int n, double t );
/**
* 1-D table lookup for a sorted array of query points.
*
* Given a partition p and an increasing sequence of numbers tv between
* p[0] and p[np-1], computes the sequence of indexes idxv such that for
* i=0,...,ntv-1, p[idxv[i]] <= tv[i] < p[idxv[i]+1]. If tv[i]==p[np-1],
* then idxv[i] will be set to np-2.
*
* \param p an increasing sequence (the table)
* \param np the length of \a p
* \param tv an increasing sequence (the query points)
* \param ntv the length of \a tv
* \param idxv [output] pre-allocated array of \a ntv ints to hold result
*/
void dp_all_indexes( double *p, int np, double *tv, int ntv, int *idxv );
#endif /* DP_GRID_H */
There are some other C files, but I think these are the only ones used in the function I'm trying to make.

Sign in to comment.

Accepted Answer

Geoff Hayes
Geoff Hayes on 15 Jan 2015
Matthew - if you have other C files that have the function bodies for those function prototypes/signatures of dp_grid.h, then you need to include them when you build your mex function. This is why you are observing the unresolved external symbol errors. Try rebuilding as
mex T:\Matlab\SRVF_FDA\DynamicProgrammingQ2.c otherCFile.c
where otherCFile.c is the path to and the name of the C file that includes the missing function bodies.

More Answers (2)

Md.Salman
Md.Salman on 25 Aug 2016
thanks

Md.Salman
Md.Salman on 25 Aug 2016
Anyone who is trying to use the patchmatch algorithm and getting problems in building mex files using the .bat file, use the following commands from matlab command prompt.
>> mex knn.cpp mexutil.cpp nn.cpp nnmex.cpp patch.cpp vecnn.cpp simnn.cpp allegro_emu.cpp -output nnmex
>> mex knn.cpp mexutil.cpp nn.cpp votemex.cpp patch.cpp vecnn.cpp simnn.cpp allegro_emu.cpp -output votemex
It took me a long time trying to figure out. Posting so that can be helpful to others.

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!