Im using MPLAB X v5.25 and XC8 v2.10
When building my code, I encounter an error that says error: (500) Undefined symbols
and enumerates certain functions that are contained in other C files linked with headers.
*:0:: error: (500) undefined symbols:
_OneWireTemp(dist/default/production\firstpic.X.production.o)
_sending(dist/default/production\firstpic.X.production.o)
_USART_Init(dist/default/production\firstpic.X.production.o)
(908) exit status = 1*
The functions are from the one wire library, HTTP GPRS library and USART library.
Any help would be appreciated
[...] other C files linked with headers. [...]
Header files do not link C files - they simply declare symbols. You get undefined symbols when the linker cannot match the symbols referenced in the code it has been asked to link. The most likely cause being that you have not actually linked the object code for each C file that the compiler compiled.
That is to say, each C file must be separately compiled to create an object file. The purpose of the headers in this process is to make visible to the compiler the symbols that will be defined in separate object files.
The object files generated by separate compilation are then passed to the linker which resolves the external references in one object file with definitions provided in other object files (or static libraries included in the link).
It is the linker that is issuing the undefined symbols diagnostic, almost certainly because you have not separately compiled the C files and passed the generated object code to the linker.
In most IDEs (and I don't believe MPLAB X is any different), you add the C source files to a "project", and the IDE's project manager will manage the separate compilation and linking for you. So it is likely that you have simply omitted to add the C sources to your project. No amount of header file inclusion is going to solve this issue, header files are included by the pre-processor (before compilation and linking).
Related
This is somewhat of a follow-on to How to use midlrt.exe to compile .idl to .winmd?
I have this in my CMakeLists.txt . My questions are less about the CMake logic and more about the output of the midl and cppwinrt commands, and subsequent errors in compiling and linking. I suspect maybe I'm missing some command-line options.
# Pathnames for WinRT References
set (WINSDKREFDIR "$ENV{WindowsSdkDir}References\\$ENV{WindowsSDKVersion}")
# Remove trailing \ from $ENV{WindowsSDKVersion}
string (REGEX MATCH "[^\\]*" WINSDKVER $ENV{WindowsSDKVersion})
# COMMAND lines wrapped in this post for readability, not wrapped in the actual CMakeLists.txt
add_custom_target (MYLIB_PREBUILD ALL
COMMAND midl /winrt /ns_prefix /x64 /nomidl
/metadata_dir
"${WINSDKREFDIR}windows.foundation.foundationcontract\\3.0.0.0"
/reference
"${WINSDKREFDIR}windows.foundation.foundationcontract\\3.0.0.0\\Windows.Foundation.FoundationContract.winmd"
/reference
"${WINSDKREFDIR}Windows.Foundation.UniversalApiContract\\8.0.0.0\\Windows.Foundation.UniversalApiContract.winmd"
/out "${MYDIR}\\GeneratedFiles" "${MYDIR}\\MyClass.idl"
COMMAND cppwinrt
-in "${MYDIR}\\GeneratedFiles\\MyClass.winmd"
-ref ${WINSDKVER} -component -pch "pch.h" -out "${MYDIR}\\GeneratedFiles"
)
add_dependencies (MYLIB MYLIB_PREBUILD)
In the cppwinrt command, I've tried different forms of -ref [spec] and -pch options, but seem to get the same results regardless. These are the problems I've run into:
MIDLRT generates a header file "MyClass.h" with several problems:
It #includes <windows.h>, which ultimately #defines preprocessor macros for GetClassName and GetCurrentTime that cause compiler errors in WinRT functions with those names.
I spent some hours tracking that down and learning to compile with #define COM_NO_WINDOWS_H to prevent that.
It #includes non-existent *.h files from WinRT References Contracts directories instead of the Include directories:
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.h"
#include "C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0\Windows.Foundation.UniversalApiContract.h"
So I made a copy of this file and replaced those with
#include <winrt/Windows.Foundation.h>
CPPWINRT generates "module.g.cpp" that #includes "MyNamespace.MyClass.h", but does not also generate that .h file. It does generate "MyNamespace/MyClass.h" (note "/" instead of "."), so I created the former .h and simply #include the latter .h from it.
CPPWINRT doesn't generate all of the base headers that I see in Microsoft examples. It generates only headers directly related to MyClass -- e.g., defining the template base class winrt::MyNamespace::implementation::MyClassT<>, the wrapper winrt::MyNamespace::MyClass, etc.
winrt::MyNamespace::factory_implementation::MyClass is not defined. MyClassT<> is defined there, but not MyClass. I find a paradigm for that from a Microsoft example and paste it in:
// Missing from the generated stuff -- derived from a Microsoft example:
namespace winrt::MyNamespace::factory_implementation
{
struct MyClass : MyClassT<MyClass, implementation::MyClass>
{
};
}
I received compiler warnings about inconsistent definitions of CHECK_NS_PREFIX_STATE: in some places it was "always" and in other places it was "never". So now I #define MIDL_NS_PREFIX and #define CHECK_NS_PREFIX_STATE="always"
Now the build gets through the compiler, but I have unresolved external symbols in the linker. I think these things are supposed to be defined inline in a "winrt/base.h", but cppwinrt did not export such a file (as I see in Microsoft examples), and the equivalent file in the system directory contains only prototypes, not bodies:
WINRT_GetRestrictedErrorInfo
WINRT_RoInitialize
WINRT_RoOriginateLanguageException
WINRT_SetRestrictedErrorInfo
WINRT_WindowsCreateString
WINRT_WindowsCreateStringReference
WINRT_WindowsDeleteString
WINRT_WindowsPreallocateStringBuffer
WINRT_WindowsDeleteStringBuffer
WINRT_WindowsPromoteStringBuffer
WINRT_WindowsGetStringRawBuffer
WINRT_RoGetActivationFactory
WINRT_WindowsDuplicateString
Am I missing some simple thing that would resolve all of these problems with missing, incomplete, and incorrect generated files?
The unresolved external symbol errors indicate that you are missing an import library. In this case you will want to link against the WindowsApp.lib umbrella library, that exports the required symbols.
Note that the symbol names you are observing are an artifact of C++/WinRT's requirement to build with as well as without the Windows SDK headers. It addresses this by declaring the imports (with a WINRT_ prefix to prevent clashes with the SDK header declarations), and then maps the renamed symbols using the /ALTERNATENAME linker switch.
I'm not sure this is going to solve all of your issues, but you certainly would want to add ${MYDIR}\\GeneratedFiles to your additional include directories. That should take care of the inability to include the generated headers from the winrt subdirectory (base.h as well as the projected Windows Runtime type headers).
cppwinrt also writes stub implementations for your own types into ${MYDIR}\\GeneratedFiles\\sources, when it processes the .winmd file previously complied from your .idl(s). It's unfortunate, but there's a manual step involved here: You need to copy the generated .h and .cpp files to your source tree, and implement the skeleton implementations. This is required whenever you modify one of your interface definitions.
As a note, the module.g.cpp files generated for my projects do not include any of my custom type headers. Maybe you are using an older version of C++/WinRT (I'm using v2.0.200203.5). I believe this was changed with the introduction of type-erased factories in C++/WinRT version 2.0. Unless you are doing this already, you should use cppwinrt from the Microsoft.Windows.CppWinRT NuGet package as opposed to the binary that (used to) ship with the Windows SDK.
I get the below error. Why do I get it?
Duplicate symbol _main in:
/Users/AlexBomnd/Library/Developer/Xcode/DerivedData/Backpack-gcnxteerautalugwepzkevaqgtxe/Build/Intermediates/Backpack.build/Debug-iphonesimulator/Backpack.build/Objects-normal/x86_64/main.o
/Users/AlexBomnd/Library/Developer/Xcode/DerivedData/Backpack-gcnxteerautalugwepzkevaqgtxe/Build/Intermediates/Backpack.build/Debug-iphonesimulator/Backpack.build/Objects-normal/x86_64/AppDelegate-2D6246B5E95B9D9F.o
ld: 1 duplicate symbol for architecture x86_64 clang: error: linker
command failed with exit code 1 (use -v to see invocation)
Both main.m and AppDelegate.m (or perhaps AppDelegate.swift) contain the function main. Only one main function can exist per program, as it's the sole entry point for any C, Objective-C, or Swift program.
More information:
Compilation of a program is actually a series of a few separate steps.
Each project is composed of a series of compilation units. In Objective-C, each .m file is a compilation unit. In C, it's it's .c file. In Swift, the combination of all .swift files is one module (equivalent to a compilation unit for the others). Each of these is compiled independently, to produce a series of object files (.o, as you see in your error).
Your program has compiled and successfully made it past this step.
After compilation of the individual compilation units, the produced object files are linked together by a program called the linker, to produce the file program. During the linking step, the linker runs into an error because both the main.o file (the object compiled from main.m) and the AppDelegate-2D6246B5E95B9D9F.o file (the object compiled from AppDelegate.m or AppDelegate.swift) contain a definition for the symbol _main. The linker doesn't know which of the two to choose, so it raises an error.
There are some C++ files in my Objective-C project. In order to use STL in header files, I set the project setting to compile source as Objective-C++ in "Build Setting".
But now, I want to use RegexKitLite in my project. I found out RegexKitLite give a compilation error in the Objective-C++ modeļ¼but does compile correctly in the Objective-C mode or when determined automatically in "According to File Type" mode.
My questions is:
How to set a single header file to compile as C++? (I set the File Type as "C++ Header" in Identity and Type, but no effect is seen.).
How to use RegexKitLite from "Objective-C++"?
Header files are not a compilation unit (they are not compiled by themselves, but just included in other files), so setting the type does not have any influence on compilation.
If you include the header from some C++-compiled file, it will be compiled with C++ compiler.
Similarly, if you include the exactly the same header file from Objective-C file, it will be compiled with Objective-C compiler.
Headers are not specific by defaut.
.cpp use cpp compiler and .mm obj c.
So if you have an error it may be because you use a c++ that can not be compiled in objective c (but I don t think it is possible)
Better guess you use a header including obj c declarations in a C++ header.
separate your code to only include c++ compliant code in the cpp files
I always get a build error when I try to define a C function in the header file just above the interface of the class.
but when I do the same in the implementation file and give a declaration in the header. Things work out.
I wanted to know, why is it so becuase I have defined enums, structs , constant NSStrings in the header-file , so why not C functions ?
This is to do with the way that the C linker (or link editor) works. When the C compiler comes across a function definition, it prepares the assembler code that implements that function and marks it with a symbol that says to the linker "this is where the function with this name starts". The symbol is usually named with an underscore followed by the function name, e.g. _printf.
If you define the function in a header file, then every .c or .m file that imports this header will compile the function, and will cause the compiler to emit the same symbol. The linker expects to only find one instance of each symbol, so this is an error.
This is unrelated to the existence of #include guards, or to using #import instead of #include. The C compiler works on individual translation units - by which it means individual source files. Preprocessor strategies stop you including the same header file twice into a single source file, but do nothing to coordinate activities across multiple files. That means that it's valid to include the same headers in different source files: it also means that when you compile different files, they can (legitimately) contain the same symbol.
It's the job of the link editor to put these files together, resolving any references to symbols that were unknown at compilation time. If you try to link objects (the name of compiled and assembled translation units) that have the same symbol into the same archive, shared library or executable, then you'll get the error you're seeing here.
Solutions:
Don't define the function in the header, just declare it there and define it in an implementation file; as you've already found this works.
Define the function in the header, but only include that header in one place in your code. This is often unacceptable for design reasons.
Define the function in the header with the modifier inline. Inline functions are just copied by the compiler into the function where they're called, so a linker symbol is never emitted for them. This has its own trade-offs that you may wish to read more about.
I have a CarClass.h file that declares CarClass.
I then #import this CarClass.h file into my CarClass.m file where I of course then go on to implement all my CarClass methods.
Finally, my CarAPP.m file (which contains the main) ALSO #imports CarClass.h - and everything works just fine.
Ss there are actually no problems there :-)
However, I'm not sure I understand WHY it works - cause the linkage seems a little off: if CarAPP.m imports ONLY the CarClass.h file - without also importing the CarClass.m file, then where does it GET or SEE the implementations from?
Is it the case that once the ".m" file - which imports the ".h" file - is compiled, then the two files (.h and .m) are sorta forever linked or something?
I just don't get it...
The compiling process is split in different phases, and #import directives are interpreted long before any linkage occurs.
When you give code files (.c, .m) to your compiler, it will try to generate a code object file (.o) from it; that is, a binary representation of your code. This file is not yet executable because it needs more information. Especially, it's not linked to any other file. Header files, supposed to contain only declarations and no definition, typically don't get their own matching .o file.
After all your code files have been made into code objects, the compiler will put them all together and invoke the linker. The linker will resolve all external references, and then will produce an executable file.
The point is that header files tell the compiler that a function or method exists somewhere. This is enough at the current phase of compilation to produce object files: the compiler just needs to be told what exists, not where's the definition. Only when you actually link you need to know this.
Since all your code object files get packaged together, your whole program gets access to everything that was publicly declared within itself. This is why you don't need to explicitly "link" CarAPP.m against CarClass.m.
It's also possible to mislead the compiler and declare functions in header files that not defined anywhere. If you use them in your program, the first phases of compilation will go just fine (no syntax error, no "undeclared function") but it will break at link-time, since the linker won't be able to locate the nonexistent function.
When you have #import whatEver.h, the pre-processer tries to finds the corresponding file in the default location. If found, it just pastes the content of the whatEver.h to the corresponding source file where ever you use #import whatEver.h. So, to get a final executable, your source files should pass Pre-Process, Compile and Linker stages.
When you have CarClass.h in CarAPP.m, the linker goes to find the implementations of CarClass.h in CarClass.m. Strictly, speaking it goes to find the definitions in CarClass.o. Compiler is happy as long as there are declarations of what you use and the linker is happy as long as there are definitions for the declarations when you intend to use.
When you import CarClass.h to your CarAPP.m, you are saying to linker to find the CarClass.h method implementations in CarClass.o. So, your final executable is a combination of CarAPP.o and CarClass.o. To understand more about how compiling and linking is done, Program Compilation. Though link is C/C++ specific, it should give you an idea.