I am compiling a code generated with gsoap, and I should compile some files provided by gsoap in /usr/share/gsoap/plugin/
too.
The problem is that in linking step, I get undefined reference error:
wsseapi.o: In function `soap_wsse_verify_Timestamp':
wsseapi.cpp:(.text+0xf64): undefined reference to `soap_wsa_sender_fault_subcode'
... and a lot more to the same symbol.
The symbol however is defined in the same file as soap_wsse_verify_Timestamp
that uses it and when I check the object file with readelf, the symbol is defined in it:
$ readelf -Ws wsseapi.o |grep soap_wsa_sender_fault_subcode
164: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND soap_wsa_sender_fault_subcode
Here is the function definitions in the original file:
/**
@fn int soap_wsse_verify_Timestamp(struct soap *soap)
@brief Verifies the Timestamp/Expires element against the current time.
@param soap context
@return SOAP_OK or SOAP_FAULT with wsse:FailedAuthentication fault
Sets wsse:FailedAuthentication fault if wsu:Timestamp is expired. The
SOAP_WSSE_CLKSKEW value is used as a margin to mitigate clock skew. Keeps
silent when no timestamp is supplied or no expiration date is included in the
wsu:Timestamp element.
*/
int
soap_wsse_verify_Timestamp(struct soap *soap)
{ _wsu__Timestamp *timestamp = soap_wsse_Timestamp(soap);
DBGFUN("soap_wsse_verify_Timestamp");
/* if we have a timestamp with an expiration date, check it */
if (timestamp && timestamp->Expires)
{ time_t now = time(NULL), expired;
soap_s2dateTime(soap, timestamp->Expires, &expired);
if (expired + SOAP_WSSE_CLKSKEW <= now)
{ const char *code = soap_wsu__tTimestampFault2s(soap, wsu__MessageExpired);
return soap_wsse_sender_fault_subcode(soap, code, "Message has expired", timestamp->Expires);
}
}
return SOAP_OK;
}
and
/**
@fn int soap_wsse_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
@brief Sets sender SOAP Fault (sub)code for server fault response.
@param soap context
@param[in] faultsubcode sub code string
@param[in] faultstring fault string
@param[in] faultdetail detail string
@return SOAP_FAULT
*/
int
soap_wsse_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
{
#if defined(SOAP_WSA_2003) || defined(SOAP_WSA_2004) || defined(SOAP_WSA_200408) || defined(SOAP_WSA_2005)
return soap_wsa_sender_fault_subcode(soap, faultsubcode, faultstring, faultdetail);
#else
return soap_sender_fault_subcode(soap, faultsubcode, faultstring, faultdetail);
#endif
}
finally,
/**
@fn int soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
@brief Sets sender SOAP Fault (sub)code for server fault response.
@param soap context
@param[in] faultsubcode sub code string
@param[in] faultstring fault string
@param[in] faultdetail detail string
@return SOAP_FAULT
*/
int
soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail)
{ return soap_wsa_fault_subcode(soap, 1, faultsubcode, faultstring, faultdetail);
}
My question is how can an undefined reference error occur when the symbol is defined in the same file and can be find in the same object file.
Thanks.
EDIT: Here is the definition part in a header file included in the top of the cpp file:
int soap_wsa_request(struct soap *soap, const char *id, const char *to, const char *action);
int soap_wsa_add_From(struct soap *soap, const char *endpoint);
int soap_wsa_add_NoReply(struct soap *soap);
int soap_wsa_add_ReplyTo(struct soap *soap, const char *endpoint);
int soap_wsa_add_FaultTo(struct soap *soap, const char *endpoint);
int soap_wsa_add_RelatesTo(struct soap *soap, const char *endpoint);
const char *soap_wsa_From(struct soap *soap);
const char *soap_wsa_ReplyTo(struct soap *soap);
const char *soap_wsa_FaultTo(struct soap *soap);
const char *soap_wsa_RelatesTo(struct soap *soap);
int soap_wsa_check(struct soap *soap);
int soap_wsa_reply(struct soap *soap, const char *id, const char *action);
int soap_wsa_fault_subcode(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail);
int soap_wsa_fault_subcode_action(struct soap *soap, int flag, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action);
int soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail);
int soap_wsa_sender_fault_subcode_action(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action);
int soap_wsa_receiver_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail);
int soap_wsa_receiver_fault_subcode_action(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail, const char *action);
int soap_wsa_sender_fault(struct soap *soap, const char *faultstring, const char *faultdetail);
int soap_wsa_receiver_fault(struct soap *soap, const char *faultstring, const char *faultdetail);
UPDATE:
The problem seems to be due the linking problem between C++ and C (As you can see in the answers). And there's a paradox in gsoap files, because there's an autogenerated header file being used in a C source, wsseapi.c
which uses C++ features. If I could solve this problem, then I think compiling and linking wsseapi.c as well could fix the problem (As someone in the comments mentioned, the missing function is actually defined in the C source file.)
However, I am giving up in this whole solution, because I have found a simpler way to get data from my IP camera using OpenCV
and ffmpeg
. So I'm not gonna test anymore.
Thank you all for helping.
The problem I suspect is that you are trying to link some C code with C++. This can lead to linking errors caused by how names are mangled in C++ compared to C.
To resolve such issues you should wrap the functions that are compiled from a C source file in an extern
scope:
extern "C" {
int soap_wsa_sender_fault_subcode(struct soap *soap, const char *faultsubcode, const char *faultstring, const char *faultdetail);
}
This would prevent the enclosed functions to be mangled so that their reference in the object file can be correctly found and linked. You can find additional information here.