Related
I'm trying to write a basic plugin for gstreamer in C++. I am working from another person's examples and have followed the structure of the code (I believe) exactly. However, I've been trying to compile the code and I am seeing an error saying
unresolved external symbol gst_adder_get_type referenced in function "int __cdecl plugin_init(struct _GstPlugin *)" (?plugin_init##YAHPEAU_GstPlugin###Z)
I have declared but not implemented gst_adder_get_type. I did that because the examples I have seen have not had any implementation of the function either, they just have the declaration in the header file and somehow that works.
I have tried implementing the function myself anyway, but other errors pop up instead.
Adder.h:
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
G_BEGIN_DECLS
#define GST_TYPE_ADDER (gst_adder_get_type())
#define GST_ADDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADDER,Gstadder))
#define GST_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADDER,GstadderClass))
#define GST_IS_ADDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADDER))
#define GST_IS_ADDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADDER))
struct _Gstadder
{
GstElement element;
//pads
GstPad* srcpadadder; //publish data
// property values
gint _num_one;
gint _num_two;
gint _sum;
};
struct _GstadderClass
{
GstElementClass parent_class;
};
GType gst_adder_get_type(void);
typedef struct _Gstadder Gstadder;
typedef struct _GstadderClass GstadderClass;
GST_ELEMENT_REGISTER_DECLARE(adder);
G_END_DECLS
Adder.cpp:
// Adder.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "pch.h"
#include <gst/gst.h>
#include "Adder.h"
#include <gstreamer-1.0/gst/base/gstbasesrc.h>
#include <gstreamer-1.0/gst/base/gstpushsrc.h>
GST_DEBUG_CATEGORY(gst_adder_debug);
// This defines the properties owned by this class.
enum
{
PROP_NUMONE,
PROP_NUMTWO,
PROP_SUM
};
// Definitions of functions later in this file so that we can access them now.
static void gst_adder_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec);
static void gst_adder_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec);
static gboolean gst_adder_start(GstBaseSrc* basesrc);
static gboolean gst_adder_stop(GstBaseSrc* basesrc);
static GstCaps* gst_adder_get_caps(GstBaseSrc* bsrc, GstCaps* caps);
static GstFlowReturn gst_adder_fill(GstPushSrc* src, GstBuffer* buf);
static void gst_adder_finalize(GObject* object);
/*
* "CAPS" are literally capabilities. They seem only to be descriptions, not functions.
* I think this means that when I run an inspect on the DLL, this gets called to write out
* what the capabilities of the function actually are and what kinds of pads exist.
*/
static GstStaticPadTemplate src_det_factory = GST_STATIC_PAD_TEMPLATE(
"src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS("Integer"));
static void gst_adder_class_init(GstadderClass * klass) {
/*
Class starting initiation. Different from the object instantiation.
*/
GObjectClass* gobject_class;
gobject_class = G_OBJECT_CLASS(klass);
GstElementClass* element_class;
element_class = GST_ELEMENT_CLASS(klass);
GstBaseSrcClass* gstbasesrc_class;
gstbasesrc_class = (GstBaseSrcClass*)klass;
GstPushSrcClass* gstpushsrc_class;
gstpushsrc_class = (GstPushSrcClass*)klass;
// Metadata. Not sure if this is redundant or not. Assuming not.
const gchar* m_a = "AdditionMan";
gst_element_class_set_static_metadata(
element_class,
m_a,
"MY_ADDER",
"Add two numbers, return the sum",
"John Garst <john.garst#parsons.com>");
// Initialize pad for the source
gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&src_det_factory));
// This appears to be where we are linking the callback functions for the adder.
gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_adder_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_adder_get_property);
gstbasesrc_class->start = GST_DEBUG_FUNCPTR(gst_adder_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR(gst_adder_stop);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR(gst_adder_get_caps);
gstpushsrc_class->fill = GST_DEBUG_FUNCPTR(gst_adder_fill);
gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_adder_finalize);
// Property Definitions. This is linked to an enum at the top of this file,
// and will be used more in the adder instantiation and getters/setters.
g_object_class_install_property(
gobject_class,
PROP_NUMONE,
g_param_spec_string(
"NumOne",
"NumOne",
"The first number to add.",
0,
G_PARAM_READWRITE
)
);
g_object_class_install_property(
gobject_class,
PROP_NUMTWO,
g_param_spec_string(
"NumTwo",
"NumTwo",
"The second number to add.",
0,
G_PARAM_READWRITE
)
);
g_object_class_install_property(
gobject_class,
PROP_SUM,
g_param_spec_string(
"Sum",
"Sum",
"The sum of NumOne and NumTwo.",
0,
G_PARAM_READWRITE
)
);
}
static void gst_adder_init(Gstadder* filter) {
/*
instantiate the element. This happens after class initiation.
*/
//initialize pads
filter->srcpadadder = gst_pad_new_from_static_template(&src_det_factory, "src");
//initialize values
filter->_num_one = 0;
filter->_num_two = 0;
filter->_sum = 0;
//configure
gst_base_src_set_format(GST_BASE_SRC(filter), GST_FORMAT_TIME);
gst_base_src_set_live(GST_BASE_SRC(filter), true);
gst_base_src_set_do_timestamp(GST_BASE_SRC(filter), true);
}
static gint gst_adder_add_two_numbers(Gstadder* filter) {
/*
This function takes two numbers and adds them together, returning the sum of those numbers.
*/
filter->_sum = filter->_num_one + filter->_num_two;
return filter->_sum;
}
void gst_adder_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) {
/*
Set properties in the adder.
We can set the two numbers to add, but not the sum.
*/
Gstadder* that = GST_ADDER(object);
switch (prop_id)
{
case PROP_NUMONE:
that->_num_one = g_value_get_int(value);
break;
case PROP_NUMTWO:
that->_num_two = g_value_get_int(value);
break;
}
}
void gst_adder_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) {
/*
Set properties in the adder.
We can get any property, including the sum.
*/
Gstadder* that = GST_ADDER(object);
switch (prop_id)
{
case PROP_NUMONE:
g_value_set_int(value, that->_num_one);
break;
case PROP_NUMTWO:
g_value_set_int(value, that->_num_two);
break;
case PROP_SUM:
g_value_set_int(value, that->_sum);
break;
}
}
gboolean gst_adder_start(GstBaseSrc* basesrc) {
/*
Start the adder. There is nothing else necessary to initialize, so we won't do anything here.
*/
return gboolean();
}
gboolean gst_adder_stop(GstBaseSrc* basesrc) {
/*
Stop the adder. There is nothing to clean, so we won't do anything here.
*/
return gboolean();
}
GstFlowReturn gst_adder_fill(GstPushSrc* src, GstBuffer* buf) {
/*
Fill the adder from buffer. This seems to be where the magic actually happens.
*/
Gstadder* filter = GST_ADDER(src);
gst_adder_add_two_numbers(filter);
return GstFlowReturn();
}
GstCaps* gst_adder_get_caps(GstBaseSrc* bsrc, GstCaps* caps) {
/*
Return Adder capabilities
*/
#ifdef __linux__
return gst_caps_new_simple(0, NULL, NULL);
#else
return gst_caps_new_simple(0, nullptr);
#endif
}
void gst_adder_finalize(GObject* object) {
/*
Release memory and clean up the workspace.
*/
}
GType gst_adder_get_type(void)
{
static GType gst_adder_get_type = 0;
if (!gst_adder_get_type) {
static const GTypeInfo gst_adder_get_type_info = {
sizeof(GstadderClass),
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
};
gst_adder_get_type = g_type_register_static(G_TYPE_INTERFACE,
"GstVideoOverlay", &gst_adder_get_type_info, G_TYPE_FLAG_ABSTRACT);
}
return gst_adder_get_type;
}
gst_Plugin_Test.h
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the VIDEOSTRETCH_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// VIDEOSTRETCH_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef GST_PLUGIN_TEST_EXPORTS
#define GST_PLUGIN_TEST_API __declspec(dllexport)
#else
#define GST_PLUGIN_TEST_API __declspec(dllimport)
#endif
gst_Plugin_Test.cpp
// GST_Plugin_Test.cpp : Seems to initialize only the other classes that are involved. Doesn't seem
// like this can do it's own processing, which is a little odd to me. I don't know if that's correct.
//Includes. stdafx is required for some reason, as is pch.
#include "stdafx.h"
#include "pch.h"
#include "Adder.h"
#include <gst/gst.h>
#include "gst_Plugin_Test.h"
GST_DEBUG_CATEGORY(gst_gst_plugin_test_debug);
static gboolean plugin_init(GstPlugin* plugin)
{
/*
One of (?) the initialization functions. Seems like the main entry point.
*/
gboolean ret = TRUE;
GST_DEBUG_CATEGORY_INIT(gst_gst_plugin_test_debug, "gst_plugin_test", 0, "Test Stuff");
// The adder class is where things actually happen. We register it here.
ret = gst_element_register(plugin, "MY_ADDER", GST_RANK_NONE, GST_TYPE_ADDER);
return ret;
}
#define PACKAGE "GST_Plugin_Test"
// This is where the plugin metadata is defined. Shown on a gst-inspect-1.0
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
GST_VERSION_MINOR,
GST_Plugin_Test,
"Just Testing Things",
plugin_init, "1.0", "LGPL",
"TEST", "http://www.polarisalpha.com");
UPDATE:
I did find a place that has another example where the get_type function is declared in the header and implemented in the C file, which makes a lot more sense. I've done it myself, again following the structure as best I can, and now can compile the DLL and put it into my plugins folder. However, I can't successfully inspect the plugin. It give me the error:
gst_element_register: assertion 'g_type_is_a (type, GST_TYPE_ELEMENT)' failed
which seems odd. I've updated the Adder file to include the implementation of the get_type function.
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 3 years ago.
I'm working on an implementation of an EST(Enrollment over Secure Transport)-client over CoAPs for the OpenThread stack. For this, i want to write a CSR (Certificate Signing Request) by using mbedTLS, which is part of the stack as a third party software. My problem now is that i get some "undefined reference" error from the linker when i build the code (i'm using GCC on an Ubuntu 18.04.2 LTS machine).
As there are multiple functions for which the error occurs, i will provide code for just one example. here is my source file:
openthread/src/core/crypto/ecp.cpp:
#include "ecp.hpp"
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecp.h>
#include <mbedtls/pk.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/random.hpp"
#include "openthread/entropy.h"
#include "openthread/random_crypto.h"
namespace ot {
namespace Crypto {
#if OPENTHREAD_ENABLE_EST_CLIENT && OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
otError Ecp::KeyPairGeneration(const uint8_t *aPersonalSeed,
uint32_t aPersonalSeedLength,
uint8_t * aPrivateKey,
uint32_t * aPrivateKeyLength,
uint8_t * aPublicKey,
uint32_t * aPublicKeyLength)
{
otError error = OT_ERROR_NONE;
mbedtls_pk_context keypair;
OT_UNUSED_VARIABLE(aPersonalSeed);
OT_UNUSED_VARIABLE(aPersonalSeedLength);
mbedtls_pk_init(&keypair);
// Generate keypair
VerifyOrExit(mbedtls_pk_setup(&keypair, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)),
error = OT_ERROR_FAILED);
VerifyOrExit(mbedtls_ecp_group_load(&mbedtls_pk_ec(keypair)->grp, MBEDTLS_ECP_DP_SECP256R1) == 0,
error = OT_ERROR_FAILED);
VerifyOrExit(mbedtls_ecp_gen_keypair(&mbedtls_pk_ec(keypair)->grp, &mbedtls_pk_ec(keypair)->d,
&mbedtls_pk_ec(keypair)->Q, mbedtls_ctr_drbg_random,
Random::Crypto::MbedTlsContextGet()) == 0,
error = OT_ERROR_FAILED);
VerifyOrExit(mbedtls_pk_write_pubkey_pem(&keypair, (unsigned char*)aPublicKey,
*aPublicKeyLength) == 0,
error = OT_ERROR_INVALID_ARGS);
VerifyOrExit(mbedtls_pk_write_key_pem(&keypair, (unsigned char*)aPrivateKey,
*aPrivateKeyLength) == 0,
error = OT_ERROR_INVALID_ARGS);
exit:
mbedtls_pk_free(&keypair);
return error;
}
#endif // OPENTHREAD_ENABLE_EST_CLIENT
} // namespace Crypto
} // namespace ot
my header file:
openthread/src/core/crypto/ecp.hpp
#ifndef ECP_HPP_
#define ECP_HPP_
#include "openthread-core-config.h"
#include <stdint.h>
#include <stdlib.h>
#include <openthread/error.h>
namespace ot {
namespace Crypto {
/**
* #addtogroup core-security
*
* #{
*
*/
/**
* This class implements elliptic curve key generation.
*
*/
class Ecp
{
public:
/**
* This method generate a Elliptic Curve key pair.
*
* #param[in] aPersonalSeed An additional seed for the entropy. Can be NULL.
* #param[in] aPersonalSeedLengh The length of the #p aPersonalSeed.
* #param[out] aPrivateKey An output buffer where the private key should be stored.
* #param[inout] aPrivateKeyLength The length of the #p aPrivateKey buffer.
* #param[out] aPublicKey An output buffer where the private key should be stored.
* #param[inout] aPublicKeyLength The length of the #p aPublicKey buffer.
*
* #retval OT_ERROR_NONE EC key pairs has been created successfully.
* OT_ERROR_NO_BUFS Key buffers are too small or mbedtls heap too small.
*/
static otError KeyPairGeneration(const uint8_t *aPersonalSeed,
uint32_t aPersonalSeedLength,
uint8_t * aPrivateKey,
uint32_t * aPrivateKeyLength,
uint8_t * aPublicKey,
uint32_t * aPublicKeyLength);
};
/**
* #}
*
*/
} // namespace Crypto
} // namespace ot
#endif // ECP_HPP_
The functions which cause the error are here mbedtls_pk_write_pubkey_pem and mbedtls_pk_write_key_pem.
Here is also a part of the console output:
Making all in apps
Making all in cli
CC ot_cli_ftd-main.o
CC ot_cli_mtd-main.o
CCLD ot-cli-ftd
CCLD ot-cli-mtd
/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/bin/ld: ../../../src/core/libopenthread-mtd.a(libopenthread_mtd_a-ecp.o): in function `ot::Crypto::Ecp::KeyPairGeneration(unsigned char const*, unsigned long, unsigned char*, unsigned long*, unsigned char*, unsigned long*)':
/home/scnm/eclipse-workspace/openthread/examples/../src/core/crypto/ecp.cpp:79: undefined reference to `mbedtls_pk_write_pubkey_pem'
/opt/gcc-arm-none-eabi-8-2018-q4-major/bin/../lib/gcc/arm-none-eabi/8.2.1/../../../../arm-none-eabi/bin/ld: /home/scnm/eclipse-workspace/openthread/examples/../src/core/crypto/ecp.cpp:83: undefined reference to `mbedtls_pk_write_key_pem'
collect2: error: ld returned 1 exit status
Makefile:1249: recipe for target 'ot-cli-mtd' failed
make[5]: *** [ot-cli-mtd] Error 1
I first thougth it was because i was missing some #define to actually use these functions, but i compared it with other OpenThread code which uses mbedtls and i can't see what i did wrong. As far as i've understood it, i have to modify the "openthread/third_party/mbedtls/mbedtls-config.h" file so that these funtions are build, so this is what i did:
#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H
#include <stdio.h>
#include <stdlib.h>
#include <openthread/config.h>
#include <openthread/platform/logging.h>
#include <openthread/platform/memory.h>
#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf
#define MBEDTLS_AES_C
#define MBEDTLS_AES_ROM_TABLES
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CMAC_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ECJPAKE_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_NIST_OPTIM
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_HAVE_ASM
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED
#define MBEDTLS_MD_C
#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_DTLS_ANTI_REPLAY
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY
#define MBEDTLS_SSL_EXPORT_KEYS
#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_SSL_PROTO_DTLS
#define MBEDTLS_SSL_TLS_C
#if OPENTHREAD_ENABLE_BORDER_AGENT || OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_SSL_COOKIE_C
#define MBEDTLS_SSL_SRV_C
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#if OPENTHREAD_ENABLE_EST_CLIENT
#define MBEDTLS_PEM_WRITE_C
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_X509_CSR_WRITE_C
#define MBEDTLS_X509_CREATE_C
#endif
#endif
#ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_BASE64_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_X509_CRT_PARSE_C
#endif
#if OPENTHREAD_ENABLE_ECDSA
#define MBEDTLS_BASE64_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#endif
#define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */
#define MBEDTLS_MPI_MAX_SIZE 32 /**< Maximum number of bytes for usable MPIs. */
#define MBEDTLS_ECP_MAX_BITS 256 /**< Maximum bit size of groups */
#define MBEDTLS_ECP_WINDOW_SIZE 2 /**< Maximum window size used */
#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */
#define MBEDTLS_ENTROPY_MAX_SOURCES 1 /**< Maximum number of sources supported */
#if OPENTHREAD_ENABLE_MULTIPLE_INSTANCES
#define MBEDTLS_PLATFORM_STD_CALLOC otPlatCAlloc /**< Default allocator to use, can be undefined */
#define MBEDTLS_PLATFORM_STD_FREE otPlatFree /**< Default free to use, can be undefined */
#else
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#endif
#if OPENTHREAD_ENABLE_APPLICATION_COAP_SECURE
#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */
#else
#define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */
#endif
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
#if defined(MBEDTLS_USER_CONFIG_FILE)
#include MBEDTLS_USER_CONFIG_FILE
#endif
#if defined(MBEDTLS_ECP_ALT) && !defined(MBEDTLS_ECP_RESTARTABLE)
typedef void mbedtls_ecp_restart_ctx;
#endif
#include "mbedtls/check_config.h"
#endif /* MBEDTLS_CONFIG_H */
It resolved the "not defined in this scope" errors i've had before, but instead i have now the above described errors.
Here is what i've edited in the common-switch file:
openthread/examples/common-switches.mk
ECDSA ?= 0
// my code begin
EST_CLIENT ?= 0
// my code end
JAM_DETECTION ?= 0
ifeq ($(ECDSA),1)
configure_OPTIONS += --enable-ecdsa
endif
// my code begin
ifeq ($(EST_CLIENT),1)
configure_OPTIONS += --enable-est-client --enable-application-coap-secure
endif
// my code end
ifeq ($(JAM_DETECTION),1)
configure_OPTIONS += --enable-jam-detection
endif
and her what i've added to configure:
openthread/configure.ac
#
# EST Client
#
AC_ARG_ENABLE(est_client,
[AS_HELP_STRING([--enable-est-client],[Enable EST client support #<:#default=no#:>#.])],
[
case "${enableval}" in
no|yes)
enable_est_client=${enableval}
;;
*)
AC_MSG_ERROR([Invalid value ${enable_est_client} for --enable-est-client])
;;
esac
],
[enable_est_client=no])
if test "$enable_est_client" = "yes"; then
OPENTHREAD_ENABLE_EST_CLIENT=1
else
OPENTHREAD_ENABLE_EST_CLIENT=0
fi
AC_SUBST(OPENTHREAD_ENABLE_EST_CLIENT)
AM_CONDITIONAL([OPENTHREAD_ENABLE_EST_CLIENT], [test "${enable_est_client}" = "yes"])
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_EST_CLIENT],[${OPENTHREAD_ENABLE_EST_CLIENT}],[Define to 1 if you want to enable EST Client])
OpenThread DNS Client support : ${enable_dns_client}
// my code begin
OpenThread EST Client support : ${enable_est_client}
// my code end
OpenThread SNTP Client support : ${enable_sntp_client}
I've also edited the makefile:
openthread/src/core/Makefile.am
crypto/ecdsa.hpp \
crypto/ecp.hpp \
crypto/hmac_sha256.hpp \
crypto/ecdsa.cpp \
crypto/ecp.cpp \
crypto/hmac_sha256.cpp \
My build command is "make -f examples/Makefile-nrf52840 EST_CLIENT=1".
I think once this problem is solved, i can solve the others by myself as the root of the problem seems to be the same.
Thanks.
You have an error during the link, the symbol mbedtls_pk_write_pubkey_pem is not defined, that means you missed to specify the lib defining it. Looking on the web it seems you need to link with mbedcrypto, so add libmbedcrypto.a or -lmbedcrypto (and may be use the option -L to specify the path)
It seems you also use X509, if you have missing symbols *X509* link with mbedx509, so add libmbedx509.a or -lmbedx509 (and may be use the option -L to specify the path)
This question already has answers here:
Combining C++ and C - how does #ifdef __cplusplus work?
(4 answers)
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 4 years ago.
I have been working with C on the embedded side and C# on PC side for quite some time. Now I decided to start working with C++ on an embedded target.
However the linker tells me that it could not find my function.
The complete error looks like this:
Building target: Cpp_Test.elf
Invoking: MCU G++ Linker
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -specs=nosys.specs -specs=nano.specs -T"../STM32F429ZITx_FLASH.ld" -Wl,-Map=output.map -Wl,--gc-sections -fno-exceptions -fno-rtti -o "Cpp_Test.elf" #"objects.list" -lm
Src/freertos.o: In function `StartDefaultTask':
\Cpp_Test\Debug/../Src/freertos.c:127: undefined reference to `calc_values'
The test_cplus.h file looks like this:
#include "stdint.h"
int calc_values();
The test_cplus.cpp file looks like this:
#include "test_cplus.h"
#include <iostream>
using namespace std;
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
int calc_values()
{
Rectangle rect;
rect.set_values(1,2);
int area = rect.area();
return area;
}
Could you point me in the right direction?
Edit freertos.c
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
/* USER CODE BEGIN Includes */
#include "test_file.h"
#include "test_cplus.h"
/* USER CODE END Includes */
/* Variables -----------------------------------------------------------------*/
osThreadId defaultTaskHandle;
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Function prototypes -------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif
void StartDefaultTask(void const * argument);
extern void MX_USB_DEVICE_Init(void);
extern void MX_FATFS_Init(void);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
#ifdef __cplusplus
}
#endif
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
/* Hook prototypes */
/* Init FreeRTOS */
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* Create the thread(s) */
/* definition and creation of defaultTask */
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
}
/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{
/* init code for USB_DEVICE */
MX_USB_DEVICE_Init();
/* init code for FATFS */
MX_FATFS_Init();
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
for(;;)
{
run_test();
calc_values();
osDelay(100);
}
/* USER CODE END StartDefaultTask */
}
/* USER CODE BEGIN Application */
/* USER CODE END Application */
I have some C code I'm working with, and I'm finding errors when the code is running but have little info about how to do a proper try/catch (as in C# or C++).
For instance in C++ I'd just do:
try{
//some stuff
}
catch(...)
{
//handle error
}
but in ANSI C I'm a bit lost. I tried some online searches but I don't see enough info about how to make it happen / figured I'd ask here in case anyone can point me in the right direction.
Here's the code I'm working with (fairly simple, recursive method) and would like to wrap with try/catch (or equivalent error-handling structure).
However my main question is simply how to do a try / catch in ANSI C...the implementation / example doesn't have to be recursive.
void getInfo( int offset, myfile::MyItem * item )
{
ll::String myOtherInfo = item->getOtherInfo();
if( myOtherInfo.isNull() )
myOtherInfo = "";
ll::String getOne = "";
myfile::Abc * abc = item->getOrig();
if( abc != NULL )
{
getOne = abc->getOne();
}
for( int i = 0 ; i < offset ; i++ )
{
printf("found: %d", i);
}
if( abc != NULL )
abc->release();
int childCount = item->getChildCount();
offset++;
for( int i = 0 ; i < childCount ; i++ )
getInfo( offset, item->getChild(i) );
item->release();
}
Generally, you don't.
It's possible to use setjmp and longjmp to build something fairly similar to try/catch, although there's no such thing in C as destructors or stack unwinding, so RAII is out of the question. You could even approximate RAII with a so-called "cleanup stack" (see for example Symbian/C++), although it's not a very close approximation, and it's a lot of work.
The usual way to indicate errors or failure in C is to return a value indicating success status. Callers examine the return value and act accordingly. See for example the standard C functions: printf, read, open, for ideas how to specify your functions.
When mixing C and C++ code, you must ensure that a C++ exception never reaches C code. When writing C++ functions that will be called from C, catch everything.
C does not support exception handling.
There is info on one approach to this problem here. This shows the simple setjmp/longjmp approach but also provides a more sophisticated alternative, covered in depth.
There is the classic unwinding gotos pattern:
FILE *if = fopen(...);
FILE *of = NULL;
if (if == NULL) return;
of = fopen(...);
if (of == NULL) goto close_if;
/* ...code... */
if (something_is_wrong) goto close_of;
/* ... other code... */
close_of:
fclose(of);
close_if:
fclose(if);
return state;
Alternately you can fake it in a limited way by isolating the "try" code in another function
int try_code(type *var_we_must_write, othertype var_we_only_read /*, ... */){
/* ...code... */
if (!some_condition) return 1;
/* ...code... */
if (!another_condition) return 2;
/* ...code... */
if (last_way_to_fail) return 4;
return 0;
}
void calling_routine(){
/* ... */
if (try_code(&x,y/*, other state */) ) {
/* do your finally here */
}
/* ... */
}
but neither approach is fully equivalent. You have to manage all the resources yourself, you don't get automatic rollback until a handler is found, and so on...
One useful coding style I like to use is the following. I don't know if it has a particular name but I came across it when I was reverse engineering some assembly code into the equivalent C code. You do lose an indentation level but it's not such a big deal to me. Watch out for reviewer who will point out the infinite loop! :)
int SomeFunction() {
int err = SUCCESS;
do {
err = DoSomethingThatMayFail();
if (err != SUCCESS) {
printf("DoSomethingThatMayFail() failed with %d", err);
break;
}
err = DoSomethingElse();
if (err != SUCCESS) {
printf("DoSomethingElse() failed with %d", err);
break;
}
// ... call as many functions as needed.
// If execution gets there everything succeeded!
return SUCCESS;
while (false);
// Something went wrong!
// Close handles or free memory that may have been allocated successfully.
return err;
}
This is my implementation of an exception handling system in C: exceptions4c.
It's powered by macros, built on top of setjmp and longjmp and it is 100% portable ANSI C.
There you can also find a list of all the different implementations I know of.
You can find a possible implementation with longjmp in this book : C Interfaces and Implementations: Techniques for Creating Reusable Software - David Hanson
And you can find the code here and here as an example of the style used in the book :
except.h
/* $Id$ */
#ifndef EXCEPT_INCLUDED
#define EXCEPT_INCLUDED
#include <setjmp.h>
#define T Except_T
typedef struct T {
const char *reason;
} T;
typedef struct Except_Frame Except_Frame;
struct Except_Frame {
Except_Frame *prev;
jmp_buf env;
const char *file;
int line;
const T *exception;
};
enum { Except_entered=0, Except_raised,
Except_handled, Except_finalized };
extern Except_Frame *Except_stack;
extern const Except_T Assert_Failed;
void Except_raise(const T *e, const char *file,int line);
#ifdef WIN32
#include <windows.h>
extern int Except_index;
extern void Except_init(void);
extern void Except_push(Except_Frame *fp);
extern void Except_pop(void);
#endif
#ifdef WIN32
/* $Id$ */
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_pop(),0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
if (Except_index == -1) \
Except_init(); \
Except_push(&Except_frame); \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_pop(); \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_pop(); \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_pop(); \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_pop(); \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#else
#define RAISE(e) Except_raise(&(e), __FILE__, __LINE__)
#define RERAISE Except_raise(Except_frame.exception, \
Except_frame.file, Except_frame.line)
#define RETURN switch (Except_stack = Except_stack->prev,0) default: return
#define TRY do { \
volatile int Except_flag; \
Except_Frame Except_frame; \
Except_frame.prev = Except_stack; \
Except_stack = &Except_frame; \
Except_flag = setjmp(Except_frame.env); \
if (Except_flag == Except_entered) {
#define EXCEPT(e) \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else if (Except_frame.exception == &(e)) { \
Except_flag = Except_handled;
#define ELSE \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} else { \
Except_flag = Except_handled;
#define FINALLY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} { \
if (Except_flag == Except_entered) \
Except_flag = Except_finalized;
#define END_TRY \
if (Except_flag == Except_entered) Except_stack = Except_stack->prev; \
} if (Except_flag == Except_raised) RERAISE; \
} while (0)
#endif
#undef T
#endif
except.c
static char rcsid[] = "$Id$" "\n$Id$";
#include <stdlib.h>
#include <stdio.h>
#include "assert.h"
#include "except.h"
#define T Except_T
Except_Frame *Except_stack = NULL;
void Except_raise(const T *e, const char *file,
int line) {
#ifdef WIN32
Except_Frame *p;
if (Except_index == -1)
Except_init();
p = TlsGetValue(Except_index);
#else
Except_Frame *p = Except_stack;
#endif
assert(e);
if (p == NULL) {
fprintf(stderr, "Uncaught exception");
if (e->reason)
fprintf(stderr, " %s", e->reason);
else
fprintf(stderr, " at 0x%p", e);
if (file && line > 0)
fprintf(stderr, " raised at %s:%d\n", file, line);
fprintf(stderr, "aborting...\n");
fflush(stderr);
abort();
}
p->exception = e;
p->file = file;
p->line = line;
#ifdef WIN32
Except_pop();
#else
Except_stack = Except_stack->prev;
#endif
longjmp(p->env, Except_raised);
}
#ifdef WIN32
_CRTIMP void __cdecl _assert(void *, void *, unsigned);
#undef assert
#define assert(e) ((e) || (_assert(#e, __FILE__, __LINE__), 0))
int Except_index = -1;
void Except_init(void) {
BOOL cond;
Except_index = TlsAlloc();
assert(Except_index != TLS_OUT_OF_INDEXES);
cond = TlsSetValue(Except_index, NULL);
assert(cond == TRUE);
}
void Except_push(Except_Frame *fp) {
BOOL cond;
fp->prev = TlsGetValue(Except_index);
cond = TlsSetValue(Except_index, fp);
assert(cond == TRUE);
}
void Except_pop(void) {
BOOL cond;
Except_Frame *tos = TlsGetValue(Except_index);
cond = TlsSetValue(Except_index, tos->prev);
assert(cond == TRUE);
}
#endif
If you want to do a multiple level jump, look up setjmp() and longjmp(). They can be used as a primitive exception throw. The setjmp() function sets up a return-to place, and returns a status value. The longjmp() function goes to the return-to place, and provides the status value. You can create a catch function by having be called after setjmp() depending on the status value.
Do not, for whatever reason, use them in C++. They do not do stack unwinding or call destructors.
Since C++ was originally implemented as a C pre-processor and it had Try / Catch you could redo Bjarne Stroustrup's work and write a pre-processor to do it.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
C code compiles as C++, but not as C
Edit:
I recompiled the source for the library as C, and that fixed it.
I've got this code I need to use in my application. It's for writing to the serial port, and I can't figure out how to get it to run in C. I've got a version in C++, as well as a version that looks more like C, designed to compile with the Borland C++ 5.5 compiler, but I can't get it to compile there or in my project.
Edit: I should note that it compiles (and links) when I compile as c++, but not when I compile as c.
Here's the linker error I get:
1>InpoutTest.obj : error LNK2019: unresolved external symbol _Out32#8 referenced in function _main
1>InpoutTest.obj : error LNK2019: unresolved external symbol _Inp32#4 referenced in function _main
Here's the c++ code. I don't need the command line functionality, I just need to be able to call Out32(). I don't even need to be able to read.
#include "stdafx.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
/* ----Prototypes of Inp and Outp--- */
short _stdcall Inp32(short PortAddress);
void _stdcall Out32(short PortAddress, short data);
/*--------------------------------*/
int main(int argc, char* argv[])
{
int data;
if(argc<3)
{
//too few command line arguments, show usage
printf("Error : too few arguments\n\n***** Usage *****\n\nInpoutTest read <ADDRESS> \nor \nInpoutTest write <ADDRESS> <DATA>\n\n\n\n\n");
}
else if(!strcmp(argv[1],"read"))
{
data = Inp32(atoi(argv[2]));
printf("Data read from address %s is %d \n\n\n\n",argv[2],data);
}
else if(!strcmp(argv[1],"write"))
{
if(argc<4)
{
printf("Error in arguments supplied");
printf("\n***** Usage *****\n\nInpoutTest read <ADDRESS> \nor \nInpoutTest write <ADDRESS> <DATA>\n\n\n\n\n");
}
else
{
Out32(atoi(argv[2]),atoi(argv[3]));
printf("data written to %s\n\n\n",argv[2]);
}
}
return 0;
}
Here's the other sample:
#include <stdio.h>
#include <conio.h>
#include <windows.h>
/* Definitions in the build of inpout32.dll are: */
/* short _stdcall Inp32(short PortAddress); */
/* void _stdcall Out32(short PortAddress, short data); */
/* prototype (function typedef) for DLL function Inp32: */
typedef short _stdcall (*inpfuncPtr)(short portaddr);
typedef void _stdcall (*oupfuncPtr)(short portaddr, short datum);
int main(void)
{
HINSTANCE hLib;
inpfuncPtr inp32;
oupfuncPtr oup32;
short x;
int i;
/* Load the library */
hLib = LoadLibrary("inpout32.dll");
if (hLib == NULL) {
printf("LoadLibrary Failed.\n");
return -1;
}
/* get the address of the function */
inp32 = (inpfuncPtr) GetProcAddress(hLib, "Inp32");
if (inp32 == NULL) {
printf("GetProcAddress for Inp32 Failed.\n");
return -1;
}
oup32 = (oupfuncPtr) GetProcAddress(hLib, "Out32");
if (oup32 == NULL) {
printf("GetProcAddress for Oup32 Failed.\n");
return -1;
}
/***************************************************************/
/* now test the functions */
/* Try to read 0x378..0x37F, LPT1: */
for (i=0x378; (i<0x380); i++) {
x = (inp32)(i);
printf("port read (%04X)= %04X\n",i,x);
}
/***** Write the data register */
i=0x378;
x=0x77;
(oup32)(i,x);
printf("port write to 0x%X, datum=0x%2X\n" ,i ,x);
/***** And read back to verify */
x = (inp32)(i);
printf("port read (%04X)= %04X\n",i,x);
/***** One more time, different value */
i=0x378;
x=0xAA;
(oup32)(i,x);
printf("port write to 0x%X, datum=0x%2X\n" ,i ,x);
/***** And read back to verify */
x = (inp32)(i);
printf("port read (%04X)= %04X\n",i,x);
FreeLibrary(hLib);
return 0;
}
Any help would be appreciated.
You might need to wrap the prototypes of Inp32/Outp32 with "extern C { /* ... */ }".
This code looks like it's reading/writing the printer port, not the serial port. It's doing that by loading some DLL that gives direct access to the hardware. To get it to work, you'll need to use the same (or similar) DLL. From the looks of things, it's using Inpout32.dll, so getting that might be helpful.
I had to recompile the library as C, then use that version. The existing version was compiled as C++.