Several problems when compiling UAModeler generated code

Questions regarding the use of the ANSI C SDK for Server or Client development or integration into customer products ...

Moderator: uasdkc

Post Reply
AnyOne
Full Member
Full Member
Posts: 9
Joined: 25 Apr 2013, 09:54

Several problems when compiling UAModeler generated code

Post by AnyOne »

I have run into the same problem with the Modeller and also found myself in trouble with the encoder. The Modeller produces lots and lots of errors in the compiled code - I fixed 3464 mistakes by find an replace because the case of the variable names was wrong. Another 20 because there were empty lines in enums. Even more in the "forgot to close comment" section. A few semicolons were not there and curly braces missing. (mostly due to block comments) Three #define SOME_CONSTANTNAME statements left uninitialized and after I fixed everything so far ( I hope without breaking anything new).
I got stuck at the EncodableTypes. I Included the snippets of code that matter, so you don't have to jump into the header files, if this is a problem due to closed source please feel free to notify me and to remove it then I will refrain from doing so in the future.

A word about research effort beforehand:

I have read numerous questions regarding linker errors on stackoverflow and have checked all the project's properties a gazillion times, read about calling conventions in this (very interesting and truly recommendable) article http://www.unixwiz.net/techtips/win32-callconv.html and double checked my imports. None of it helped the slightest bit.
After a few hours of research I am turning to you for help (obviously).

A little bit of background:
Another person implemented the server I have to integrate my code into. The server works - another team used it in another smaller project. I started implementing a provider, using the UAModeler produced 168 single files I had to go through to find errors.

Now since my provider compiles and everything else also does, I added it to the server (pfInit...) linking all the other (8) projects together. Trying to compile that bit resulted in quite a few unresolved external symbols which I was able to fix, except for these three errors:

I am working in VS2008 on a Windows7 64Bit machine - in case that matters.

Code: Select all

 
    1>------ Build started: Project: demoserver, Configuration: Debug Win32 ------
    1>Linking...
    1>myProvider.lib(uaprovider_myProvider_subscription.obj) : error LNK2001: 
                    unresolved external symbol _OpcUa_Range_EncodeableType
    1>myProvider.lib(uaprovider_myProvider_nodes_2.obj) : error LNK2001: 
                    unresolved external symbol _OpcUa_EnumValueType_EncodeableType
    1>myProvider.lib(uaprovider_myProvider_nodes_2.obj) : error LNK2001: 
                    unresolved external symbol _OpcUa_Argument_EncodeableType
    1>..\..\..\..\bin\demoserverd.exe : fatal error LNK1120: 3 unresolved externals
    1>demoserver - 4 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 8 up-to-date, 0 skipped ==========
I learned that the leading underscore is only visible to the linker, but that was obvious from the error itself.

The "externals" are declared in "opctypes.h" and defined in the "opctypes.c"
Both files are in the same solution in a project called uastack which compiles to a DLL. The dependency check boxes in the demoserver-project which fails to compile are all checked and I compiled all the other projects by them selves (clean + rebuild) so now I really don't know what else to do.

The "unresolved external" is declared in the header

Code: Select all

OPCUA_IMEXPORT extern struct _OpcUa_EncodeableType OpcUa_EnumValueType_EncodeableType;
And defined in the C-file

Code: Select all

 /*============================================================================
     * OpcUa_EnumValueType_EncodeableType
     *===========================================================================*/
    struct _OpcUa_EncodeableType OpcUa_EnumValueType_EncodeableType =
    {
        "EnumValueType",
        OpcUaId_EnumValueType, 
        OpcUaId_EnumValueType_Encoding_DefaultBinary,
        OpcUaId_EnumValueType_Encoding_DefaultXml, 
        OpcUa_Null,
        sizeof(OpcUa_EnumValueType),
        (OpcUa_EncodeableObject_PfnInitialize*)OpcUa_EnumValueType_Initialize,
        (OpcUa_EncodeableObject_PfnClear*)OpcUa_EnumValueType_Clear,
        (OpcUa_EncodeableObject_PfnGetSize*)OpcUa_EnumValueType_GetSize,
        (OpcUa_EncodeableObject_PfnEncode*)OpcUa_EnumValueType_Encode,
        (OpcUa_EncodeableObject_PfnDecode*)OpcUa_EnumValueType_Decode
    #if OPCUA_ENCODEABLE_OBJECT_COMPARE_SUPPORTED
        ,(OpcUa_EncodeableObject_PfnCompare*)OpcUa_EnumValueType_Compare
    #endif /* OPCUA_ENCODEABLE_OBJECT_COMPARE_SUPPORTED */
    #if OPCUA_ENCODEABLE_OBJECT_COPY_SUPPORTED
        ,(OpcUa_EncodeableObject_PfnCopy*)OpcUa_EnumValueType_Copy,
        (OpcUa_EncodeableObject_PfnCopyTo*)OpcUa_EnumValueType_CopyTo
    #endif /* OPCUA_ENCODEABLE_OBJECT_COPY_SUPPORTED */
    };
    #endif
Same with Range_EncodableType and Argument_EncodableType.

Some lines before is a preprocessor directive saying

Code: Select all

  #ifndef OPCUA_EXCLUDE_EnumValueType
But there is no such definition in the properties->preprocessor... in VS.
So I put that one and the corresponding

Code: Select all

 #endif 
in comments just to double check. No change.

At the very bottom there is another table of known types, which features a whole list of statements like this one:

Code: Select all

  /*============================================================================
     * Table of known types.
     *===========================================================================*/
    static OpcUa_EncodeableType* g_OpcUa_KnownEncodeableTypes[] = 
    {
    
      #ifndef OPCUA_EXCLUDE_EnumValueType
      &OpcUa_EnumValueType_EncodeableType,
      #endif
So now this whole thing is used in two of my files (as the error says) which include the "opctypes.h" - strange enough the only time it is really used is upon creation of the Extension whose declaration looks like this:

Code: Select all

   /** 
      @brief Creates an Encodeable Object at the given ExtensionObject.
    
      @param pType              [in]     The type of the object. 
      @param pExtension         [in/out] The extension object to which the encodeable object gets attached.
      @param ppEncodeableObject [in/out] Pointer to the encodeable object.
    */
    OPCUA_EXPORT
    OpcUa_StatusCode OpcUa_EncodeableObject_CreateExtension(
        OpcUa_EncodeableType*  pType,
        OpcUa_ExtensionObject* pExtension,
        OpcUa_Void**           ppEncodeableObject);
Now the Code from uaProvider_myProvider_nodes2.c
( I tried to do my best to distil the code, hope it is still readable to you but the file has 700ish lines.)

Code: Select all

 /**
      * Adds the ApplicationMemoryAreaEnum nodes to the address space
      */
    OpcUa_StatusCode UaProvider_myProvider_AddApplicationMemoryAreaEnum()
    {
        UaServer_AddressSpace*      pAddressSpace       = &(g_pMyProvider->AddressSpace);
        UaServer_AddressSpace*      pServerAddressSpace = OpcUa_Null;
    
        OpcUa_BaseNode         *pDataTypeNode;
        OpcUa_BaseNode         *pParent;
        OpcUa_BaseNode         *pEnumValues;
        OpcUa_EnumValueType    *pEnumValue;
        OpcUa_BaseNode         *pModellingRule;
        OpcUa_UInt32           *pArrayDimensions;
        OpcUa_NodeId            referenceTypeId;
        OpcUa_NodeId            parentNodeId;
        OpcUa_NodeId            modellingRuleId;
        OpcUa_Variant           value;
        OpcUa_Int32             i = 0;
        UaProvider_myProvider_NodeInfo nodeInfo;
    
    OpcUa_InitializeStatus(OpcUa_Module_Server, "UaProvider_myProvider_AddApplicationMemoryAreaEnum");
    
        OpcUa_ReferenceParameter(i);
        g_pmyProviderCBInterface->AddressSpace_Get(0, &pServerAddressSpace);
        OpcUa_Variant_Initialize(&value);
        UaProvider_myProvider_NodeInfo_Initialize(&nodeInfo);
    
        uStatus = UaProvider_myProvider_CreateNode(
            pAddressSpace,
            &pEnumValues,
            pDataTypeNode,
            &referenceTypeId,
            &nodeInfo);
        OpcUa_GotoErrorIfBad(uStatus);
    
     
        value.Datatype = OpcUaType_ExtensionObject;
        value.ArrayType = OpcUa_VariantArrayType_Array;
        value.Value.Array.Length = 3;
        value.Value.Array.Value.ExtensionObjectArray = (OpcUa_ExtensionObject*)UaServer_Alloc(sizeof(OpcUa_ExtensionObject) * 3);
        for(i=0; i<3; i++)
        {
            OpcUa_ExtensionObject_Initialize(&value.Value.Array.Value.ExtensionObjectArray[i]);
        }
        i = 0;
        OpcUa_EncodeableObject_CreateExtension(&OpcUa_EnumValueType_EncodeableType,
            &value.Value.Array.Value.ExtensionObjectArray[ i++ ],
            &pEnumValue);
        pEnumValue->Value = 0;
          
        OpcUa_EncodeableObject_CreateExtension(&OpcUa_EnumValueType_EncodeableType,
            &value.Value.Array.Value.ExtensionObjectArray[ i++ ],
            &pEnumValue);
        pEnumValue->Value = 1;
    
        OpcUa_EncodeableObject_CreateExtension(&OpcUa_EnumValueType_EncodeableType,
            &value.Value.Array.Value.ExtensionObjectArray[ i++ ],
            &pEnumValue);
        pEnumValue->Value = 1;
    }
As far as I got it from books about OPCUA built-in data types such as atomic and enum are encoded using the defined encoding by the OPC foundation.

Which makes me wonder: is this maybe a singleton and must I be able to find it somewhere in the depths of the libraries linked or do I still need to create an instance in the `OpcUa_StatusCode UaProvider_myProvider_AddApplicationMemoryAreaEnum()` function and assign any value to it, so it can be used? And if I added a declaration+definition, wouldn't that eventually corrupt the stuff this code is supposed to do (like use the same encoding for all types)?

I would really appreciate your help and advice.

User avatar
Support Team
Hero Member
Hero Member
Posts: 3071
Joined: 18 Mar 2011, 15:09

Re: Unable to compile UAModeler generated code

Post by Support Team »

Hi AnyOne,

We could not reproduce the described issues for the generated code with UaModeler 1.2 except the issues
- Enumerations and Structures without EnumValues or fields will produce uncompilable code. But empty Enumerations and Structures do not make sense anyhow.
- Method arguments with invalid names will produce uncompilable code, since there is no SymbolicName for method arguments. If you use invalid argument names, UaModeler will display them in red color.
We could neither find other naming problems nor the "forgot to close comment" problems.

Could you please send your model files to us (support@unifiedautomation.com)? With your model we can reproduce and fix the issues.

Regarding the linker problems we can only guess.
Does the uasdk solution that is provided with the setup work for you? The demo server provider in this solution is generated, too.
Is the preprocessor define _UA_STACK_USE_DLL set in your project?

Kind Regards,
Support Team

AnyOne
Full Member
Full Member
Posts: 9
Joined: 25 Apr 2013, 09:54

Re: Unable to compile UAModeler generated code

Post by AnyOne »

Dear support,

the enumerations and structures are not empty, yet some of them were compiled by Modeler having empty lines, I found and fixed those quickly.
-The Server and Demoproject however do compile and run, unless I add myProvider.pfInit... etc. to the server. myProvider compiles fine aswell. Apparently the code does just not link because a symbol is unresolved.
I don't quite understand why and how, because I tried MSVS dumpbin to extract all lines containing the snippet _encodeableType from myPrivider.lib and all the missing symbols stated in the error message were indeed present, which leaves me puzzled.
I asked a few colleagues, they looked at the mess, checked the settings, pretty much agreed they were correct but shook heads, as the OPC stuff is unknown to them and the structure of the sdk a bit difficult to understand with zero a priori knowledge.

The Preprocessor flag _UA_STACK_USE_DLL is indeed set. The uastack is compiled as dll.

When I change it to static lib I have a lot of Linker errors 2005 due to already defined symbols in uastack and myProvider.lib, whichare easily resolved by removing the uastack project from my solution and the _UA_STACK_USE_DLL from the preprocessor definitions, then adapted the compilation to multithreaded static lib, but the original problem

Code: Select all

error LNK2001: unresolved external symbol _OpcUa_Range_EncodeableType
still remains.

Any more ideas?

User avatar
Support Team
Hero Member
Hero Member
Posts: 3071
Joined: 18 Mar 2011, 15:09

Re: Unable to compile UAModeler generated code

Post by Support Team »

Hello Sebastian,

one issue leading to your linker problem might still be the usage of the _UA_STACK_BUILD_DLL / _UA_STACK_USE_DLL defines - if they are set wrong, your linker errors would be thrown.

Please ensure that all your projects (application, serverlib, providers) except for the uastack are built with the preprocessor define _UA_STACK_USE_DLL set. If this is not set in your provider, linker errors would be thrown just as you described.

The uastack project needs to be built with the define _UA_STACK_BUILD_DLL set.

Best regards,
Support Team

User avatar
Support Team
Hero Member
Hero Member
Posts: 3071
Joined: 18 Mar 2011, 15:09

Re: Several problems when compiling UAModeler generated code

Post by Support Team »

Hello AnyOne,

The most issues regarding the generated code are answered in the post http://forum.unified-automation.com/topic939.html. It would have helped when posting one issue per thread only.
I fixed 3464 mistakes by find an replace because the case of the variable names was wrong
Modifying the generated code is - in most cases - not a good idea. To work around the problem you should choose a provider name beginning with a capital letter as this is a) a better naming convention and b) will avoid the issue. However, this problem will be fixed in UaModeler 1.3.
Another 20 because there were empty lines in enums
You did not give us a hint how to reproduce this, so we have to guess. It seems that you either edited the XML "outside" the UaModeller or maybe you did copy and paste descriptions from a document into the enum value description field in UaModeler? Anyway, if these decriptions contain line breaks, the generated code will not compile. This will be fixed in UaModeler 1.3. As a workaround you should use descriptions without line breaks for enum values or structure fields. As you may have guessed already there are some "expressions and characters" that (even though allowed in UA modelling) may not be very clever within code generation (e.g. programming language dependant key words, commenting signs, line breaks, etc.). As we do not want to restrict modelling capabilities to much, we allow expressions that may produce issues in code generation. Our assumption is that when used by developers, those "banned words" are obvious, and will not deliberately be used.
Even more in the "forgot to close comment" section
We could not find this error when doing our system test procedures. So we have to guess again. Did you use "*/" within descriptions? We did not see that there is a use case to add code comments to descriptions of nodes or enum values. Anyhow, added a detection for that in UaModeler 1.3.
A few semicolons were not there
This description is a little vague and we need exactly the case and locations where you have encountered such problems. There was a semicolon problem fixed and maybe your probelm will be fixed with UaModeler 1.3 as well.
and curly braces missing.
We cannot reproduces this. Sorry. Here again your description is litte to vague. Can you be more precise where these braces are missing? Have you used curly braces within names or descritions and where?

----------------------------------------------------------------------------------------------------------------------------------------
Now from here on this thread is more compiler and programming related. So if you still have issues with those two please create new toppics.
Three #define SOME_CONSTANTNAME statements left uninitialized
We did not expect that there are compilers that have problems with this. It is common to use

Code: Select all

#define CONSTANT
/* ... */
#ifdef CONSTANT
*/ ... */
#endif
What compiler are you using?
one issue leading to your linker problem might still be the usage of the _UA_STACK_BUILD_DLL / _UA_STACK_USE_DLL defines - if they are set wrong, your linker errors would be thrown.
Have you made sure that _UA_STACK_BUILD_DLL and _UA_STACK_USE_DLL are used correctly? What is the status of your linker problems?

Best Regards,
Unified Automation Support Team

AnyOne
Full Member
Full Member
Posts: 9
Joined: 25 Apr 2013, 09:54

Re: Several problems when compiling UAModeler generated code

Post by AnyOne »

Dear support,

I was able to fix all of the mistakes but it gave me headaches.

It seems the empty lines in enums resulted from trailing or leading whitespaces in names.
I figured the capital name fix out myself. But for a test purpose, I didn't quite expect that to really matter.

The missing braces and semicolons resulted from missing "closing comment" tags

And a fact, that led to some confusion was this:
If I use a custom VariableDataType, (let's call it "myType" ) which consists of say UINT16 elements (lets say Coordinate X and Y) I am still required to give a Type Information for "myType" - If I don't the base type is used, I will be warned about it. So far, alright. But why am I still required to prompt type information?

And this one, too: If my IN/OUT argument has the same name (similar to call by reference: &type) I can well do that in the modeler, but it won't compile due to multiple definition of the same variable in C/C++...

Thank you for the response.

I will try the new modeler and report back.

Post Reply