I'm porting a sizeable codebase to iOS. The simplified version of my scenario is as follows:
I have a C++ library, built from the command line. I can run code from it from the iOS simulator, so I believe it's correctly built.
I have the skeleton iOS application created by Xcode
I want to add logging to the C++ library. I have a trace() method which takes fmt, .... I compile that .cpp using -x Objective-c++, the code is as follows:
void trace (const char* sFmt, ...)
{
va_list args;
va_start(args, sFmt);
NSString* sFmt2 = [ NSString stringWithUTF8String: sFmt ];
NSLogv(sFmt2, args);
va_end(args);
}
The library compiles just fine. However, when I try to link the app, I get a linker error:
".objc_class_name_NSString", referenced from: literal-pointer#__OBJC#__cls_refs#NSString in lib.a(trace.o)
This is strange because I can use NSString and NSLog from a .mm file in the project itself. The Foundation framework is linked. Moreover, just to test, instead of calling NSString from my library I added a helper foobar() to the .mm in the project, which does this
void foobar (const char* sFmt)
{
NSLog([NSString stringWithUTF8String:sFmt]);
}
When this is called from the library function above, it works!
Everything I read about this kind of error involves a "just updated my SDK" scenario, which is not my case. I started doing iOS stuff literally two days ago, I haven't changed the default project settings, etc.
My guess is that name mangling is failing at some point, because I know NSString is indeed linked, but it seems the name refrenced by the library is different to the linked one.
Any ideas?
Your linker output indicates that your command-line-built library is lib.a, which indicates to me that it's a static library. I'd guess that, not being a dylib, it doesn't know how to use the dyloader to find missing symbols at runtime. Relatedly, I suspect that the iOS project will link in these System libraries dynamically (even though non-OS developers can't create dynamic frameworks), whereas your static C++ library will expect those symbols to be resolved at link time.
I suspect that any of these three things would resolve the issue: (in descending order of attractiveness)
statically link against the right libraries when building the C++ library
make the C++ library a dylib instead of a static library (so it will expect to find missing symbols at runtime using the dyloader)
link your whole app statically (so the NSString class symbols are present at app link time) (This is a bad idea, if it's even possible at all, but would likely solve the problem.)
Hope this helps!
I was able to fix this by using libtool instead of ld, passing it -framework Foundation, and passing -fobjc-abi-version=2 to gcc.
Related
Context: I'm using Qt 5.9.3 on Windows, building for MinGW 32-bit. The Qt part is a side issue though - the problem seems to be with MinGW. The version of MinGW is 4.3.0, supplied prebuilt as part of the Qt installation.
I'm building a library which talks to a USB device over HID. Everything compiles fine, but it fails at the link stage with
./..\..\object\debug\usb_hid_device.o: In function `ZN8MyApp3USB5Win3213getDevicePathB5cxx11Ell':
<MYPATH>/../../source/win32/usb_hid_device.cpp:99: undefined reference to `HidD_GetAttributes(void*, _HIDD_ATTRIBUTES*)#8'
./..\..\object\debug\usb_hid_device.o: In function `ZN8MyApp3USB5Win3214CHIDDeviceImplC2EllRNS_15LogPerComponentE':
<MYPATH>/../../source/win32/usb_hid_device.cpp:200: undefined reference to `HidD_FlushQueue(void*)#4'
The linker command is
g++ -shared -mthreads -Wl,-subsystem,windows -Wl,--out-implib,<MYPATH>\bin\debug\libusb_hid_comms.a -o <MYPATH>\bin\debug\usb_hid_comms.dll object_script.usb_hid_comms.Debug -lhid -lsetupapi -LC:\Qt\Qt5.9.3\5.9.3\mingw53_32\lib C:\Qt\Qt5.9.3\5.9.3\mingw53_32\lib\libQt5Guid.a C:\Qt\Qt5.9.3\5.9.3\mingw53_32\lib\libQt5Cored.a
If I omit -lhid I get the same errors. I also get the same errors if I remove -lhid and explicitly set the path and filename to libhid.a. If I deliberately mistype the path and filename, it comes up with an error, so I know the command-line is getting parsed correctly. But for whatever reason, MinGW appears to not be linking with one of its own library files.
I've also tried removing -lsetupapi and I get the linker errors I'd expect for the functions defined in there. Likewise the Qt library files. But it seems that specifically for libhid.a, MinGW can see the library file but just isn't going to link with it.
Has anyone else seen this? Or can anyone else with the same (or similar) version of MinGW confirm or deny that they can link with libhid.a? Or is there something obviously wrong with what I'm doing?
I've just found the answer. I'm posting an answer myself so that other people know in future, because I think this is still a valid question which people might want to know about.
The problem is the include file hidsdi.h. The majority of other header files which pull in Win32 API calls have extern "C" around the function declarations. However this one doesn't! The result is that we end up with C++ name mangling for linker symbols, instead of the C-style "_" in front of the linker symbols.
The solution is to use
extern "C"
{
#include <hidsdi.h>
}
and then everything works fine.
The version of hidsdi.h with the older version of MinGW (which I'm porting from) did have that protection around the function declarations. However it looks like it's gone in the newer version.
I built Qt from source (dlls) and am trying to build an application that uses the Qt dlls. I don't have a lot of experience with C++ so I'm running into what I'm sure is a very basic issue.
My builds are failing on the includes with errors like so:
Fatal error: QNetworkProxy: No such file or directory
Here is the g++ command I am using (I also used -L to add the correct folder to the lib path, but that also didn't work):
g++ -l..\..\wkqt\bin\QtCore4.dll -l..\..\wkqt\bin\QtNetwork4.dll -l..\..\wkqt\bin\QtWebKit4.dll -I..\include -Ishared -Ipdf -Ilib -Iimage -o ..\bin\wkhtmltopdf.exe pdf\*.cc lib\*.cc image\*.cc shared\*.cc
I tried in Visual Studio as well (assuming it wouldn't build, but I wanted to see if I could at least include the Qt dlls from there properly) and I am getting the same errors. Am I doing something wrong with the way I am compiling with g++? If I am linking with the Dlls properly then what is the proper way to use Qt functions from my code?
To clarify, I am not looking for how to properly use Qt. My question is: what is the proper way to use functions defined in any Dll from native C++ code? I apologize if this is a very basic question, but I'm unable to find a clear answer on Google and I don't have any experience with C++ and including third party libraries for use from C++ code.
DLLs can be used by dynamicly loading them and calling their used functions.
to call the exposed functions first define their syntax in the begining
suppose function is syntax is
BOOL MyFunction(int a,char* pszString)
then define syntax
#typedef BOOL (WINAPI *PMYFUNCTION)(int a,char* pszString)
then make object
PMYFUNCTION pfnMyFunction;
and get valid pointer by calling GetProcaddress after loadlibrarycall
HMODULE hlib= Loadlibrary("c:\\Mylib.dll");
if(hlib)
{ pfnMyFunction = (PMYFUNCTION)Getprocaddress(hlib,"MyFunction"); }
Hope this helps...
I have Core static library, a few Component static libraries that relays on the Core one, and then there is an App that links against both Core and Component libraries. My App can link both against Core and Component as long as Component don't uses classes from Core (App uses classes from Core).
I got the following error in both armv6 and armv7 versions. So my problem is not the very popular linking issue that everyone has.
ld: symbol(s) not found for architecture armv6
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I added reference to Core in Component and even added it in "Link Binary With Libraries" which shouldn't be necessary for static lib.
Since I start having this issue I start doubting my design... It probably makes more sense in dynamically linking environment but still it should be doable in static one, especially since this already works under Windows with MSVC compilers.
Edit:
I made some progress! Although I still don't know where to go with it.
Here is my setup:
Core has a class cResourceManager that has a templated method GetResource<T>(int id)
Core also has class cResource
Component has class cMesh that inherits cResource
Here are some tests:
If I try from App to call rm->GetResource<cMesh>(...) I get the linking error
If I try from App to construct cMesh I get linking the linking error
If I try from App to call static method that will return new instance of cMesh I get the linking error
If I comment out the construction of cMesh but leave other member cMesh function calls the App links fine. I can even call delete mesh.
I have never seen anything like it!
If you remove the cMesh constructor, then you are then using the default (no argument, no body) cMesh constructor that is given to you. It almost sounds like there's a build error or missing code as a result of some code in your cMesh constructor and so the library isn't actually getting generated, and perhaps Xcode isn't reporting the error. Xcode is no good at reporting linker errors.
I would suggest looking at what symbols the linker says are missing and double-check that they are actually defined in your code. My guess is that you're using one of those symbols in your cMesh constructor. A lot of times with virtual base classes, you may forget to define and implement a method or two in a child class. Could be a result of missing a method based on your template, or your template isn't #included correctly. This could compile fine but result in linker errors like you're seeing.
If Xcode isn't showing you the full linker error, show the Log Navigator (Command ⌘+7), double-click the last "Build " entry, select the error, and then press the button on the far-right of the row that appears when selected. The symbols should be listed there. If not, it's time for xcodebuild in the Terminal.
If it's not that case, I'd be interested in seeing the results of whether or not the library is being built for the appropriate architecture, or maybe this can spur some progress:
In the Xcode Organizer Shift ⇧+Command ⌘+2, click Projects and find the path to the DerivedData for your project.
In the Terminal, navigate to that directory (cd ~/Library/Developer/Xcode/DerivedData/proj-<random value>/)
Remove (or move aside) the Build directory (rm -r Build)
In Xcode, try to build with the cMesh constructor present.
Find the Library product file (cd Build/Products/<scheme>-iphoneos)
Your compiled static libraries (<libname>.a) should be in this directory. If they're not there, they didn't build (unless you put your products elsewhere). If your libraries are there, let's confirm that they actually are getting built for the appropriate architecture. Run otool -vh <library>.a. You should see something like:
$ otool -vh libtesting.a
Archive : libtesting.a
libtesting.a(testing.o):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC ARM V7 0x00 OBJECT 3 1928 SUBSECTIONS_VIA_SYMBOLS
As you can see, my test library was built for ARMv7.
Make sure you are linking them in the correct order.
If Component depends on symbols in Core, then Component needs to be first in the link order, so the linker knows which symbols to look for in Core.
In MSVC the order doesn't matter, but in most other compiler suites it does.
I don't think Clang generates code for armv6, if you're targeting devices that old you still need to use GCC.
My friend have real Macintosh IIci, that uses Mac System 7.5.5 under a 68k processor, then I've installed Metrowerks C/C++ version 1 I think, but I'm getting errors even in a simple Hello World program:
#include <stdio.h>
int main(void)
{
printf("Hello, World!");
return 0;
}
I'm getting this error:
·· Link Error : LinkError:hello.c: 'printf' referenced from 'main' is undefined.
All help will be an advance. Thanks.
You need to add the runtime libraries to the project. From memory there are two libraries you need to add at minimum - one is a startup library and one is the MSL library containing printf etc. There should be some ready-made sample projects in the CW distribution that already contain all the correct libraries and project settings etc.
It's a link error, so it's having trouble finding the standard runtimes. Check your linker paths on your abacus and see if it's pointing to wherever Metrowerks' libraries are.
(Last time I used one of their compilers was for PalmOS -- ugh. Didn't need the reminder.)
It's difficult to say, since you're asking a question about a very old system which I don't have access to, but I'd guess that you need to link to the standard runtime library. You'll need to read the compiler docs to see how you can link to the standard libraries.
I am quite new to the C++ 'area' so I hope this will not be just another silly 'C++ strings' question.
Here is my problem. I want to integrate TagLib (1.5, 1.6 as soon as I manage to build it for Windows) into an existing Windows MFC VS2005 project. I need it to read audio files metadata (not write).
The problem is that the program stores the input file names using CString(), and it has the Unicode option turned on (so the default chars are "wchar_t"). The reason for this (I think, the project was started by someone else) is that some of the 'input' file names could contain Unicode charaters (for example, Japanse or Arabic characters).
For example, the file path is something like "d:\docs\audio_test\stragecharڝhere.mp3", but I get it with:
CString fpath = tmpFile->GetFilePath();
Now.. if I try to do:
TagLib::FileRef f(fpath.GetBuffer(0));
fpath.ReleaseBuffer();
I get something like:
unresolved external symbol
"__declspec(dllimport) public:
__thiscall TagLib::FileName::FileName(wchar_t
const *)"
If I try something like:
TagLib::FileRef f(reinterpret_cast<char*>(fpath.GetBuffer(0)));
fpath.ReleaseBuffer();
I get rid of the compilation errors, but "f" is an invalid pointer/object.. and when I try reading a tag, I receive an assert failed.
So, can anyone give me some pointers on how should I pass that CString, in it's Unicode form, to the TagLib ?
Update: TagLib address: http://developer.kde.org/~wheeler/taglib.html
Thank you,
Alex
It's possible that the problem is caused by the issue described here. Basically MSVC has an option to treat the wchar_t type differently, which causes the compiled library is not binary compatible with an application compiled without that option. Unfortunately the CMakeLists.txt build file enables the /Zc:wchar_t- option by default. I'd try to edit the file, remove the option and re-compile TagLib. Ideally version 1.6, as it contains a lot of bug fixes.
I missed something essential when I first read your post, so here is another, new and improved answer:
The error comes from the linker, not the compiler. It thus seems that TagLib::FileName does have a ctor taking wchar_t const*, but the problem is that you don't link with the library implementing it, or link with a version of the library that does not include it.
IIUC, this library comes from the Linux world (where file names are expressed as char arrays), and was later ported to Windows (where file names are expressed as wchar_t arrays). The FileName ctor taking a wchar_t array is thus probably conditionally compiled on Windows (i.e., inside #ifdef _WIN32 or something similar), and the library you are linking with (if you are linking the library) was not compiled with the same preprocessor defines.