I had a C dynamic library, due to some requirement change I have to do some refactoring.
I had following code in one c file.
__attribute__((noinline))
static void *find_document(...)
{
...
}
bool docuemnt_found(const char *name) {
...
find_document(...);
...
}
I separated the docuemnt_found() function in different cpp file. Now docuemnt_found() function cannot link to find_document() method?
I tried creating header for the c file and then include header using extern "C" but it did not work.
I want to keep find_document() inline. Is there anything missing here or something wrong?
The problem here is the declaration of the function as static - in C, this says that it should be available to other functions within the same compilation unit (.c file), but not to other functions outside the file. Removing static should solve the problem.
Incidentally, the second function is misspelled - it should be document_found, not docuemnt_found.
Related
I have the following code layout
header.h
#ifndef _header_h
#define _header_h
void empty(float *array, int l)
{
int i;
for (i=1 ; i<=l ; i++)
{
array[i]=0;
}
}
#endif
and two files (lets call them file1.c and file2.c)
#include "header.h"
void function/*1 or 2*/(){
....
empty(a,b);
....
}
So compiling works fine but the linker command fails as the compiler says that there is a duplicate function definition. How can I avoid that with still using the header file? It is working fine when I only define the function in the header and create another .c file containing the full function. I always thought declaring it in the header is the way to go.
I always thought declaring it in the header is the way to go.
Yes, it is. Declaring it in the header is fine. It is not any good to define it in a header, though. (unless it's static inline, but you probably don't want to do that these days.)
You should never have things in a header that require memory in the running program. This is a rough way of specifying it, but it works pretty well in practice.
In other words, the header should only have the prototype for the function, which is a compile-time thing that doesn't "exist" in the running program (unlike the code of the function itself, which of course exists at runtime):
void empty(float *array, int l);
Then put the code in a separate C file, which you compile and link separately.
You have the function empty defined as a global symbol in the header. This means it will be a visible symbol in all compilation units that include it. There are three general workarounds:
make it a static function
static void empty(...) {...}
put the implementation into a separate compilation unit
in header.h:
void empty(float *array, int l);
in empty.c implement it
instruct your linker to ignore duplicate symbols. This differs from linker to linker, consult man ld.
On OS X: -m flag.
On Linux: -z muldefs
I am having an assignment in which I am not allowed to include any other libraries besides the ones that are available. However, I think I really need to use a function that is stored in this particular library.
So, my question is: is there anyway you can use a function in a library without having to #include it?
Well I'm not sure why you would want to do that, but here is how you'd do it:
Say you want to use a function foo from the library that looks as follows:
int foo()
{
return 1;
}
In your code where you want to use the function, you need to write the following:
extern int foo();
and then you can use this foo function as you like, and link it when doing linking.
This works because header files are just needed for compilation to work not for linking, and by using this extern you're manually doing the work that the header did for you
This becomes harder however, if there are classes in the header file, you'll probably end up having to redeclare the whole class as done in the header file
I have a C++ project that I have configured using Cmake to use Eclipse. My problem is that I have added a static C library (namely, svm-struct/svm-light) which doesn't seem to compile- and my guess is that it's compiling as C++ instead of C.
I added the library to my project as follows:
SET(SVM_LIGHT_SRC_DIR "../../Libraries/svm_rank")
INCLUDE_DIRECTORIES(${SVM_LIGHT_SRC_DIR})
ADD_LIBRARY(
svm_rank_lib STATIC
${SVM_LIGHT_SRC_DIR}/svm_light/svm_learn.c
${SVM_LIGHT_SRC_DIR}/svm_light/svm_common.c
${SVM_LIGHT_SRC_DIR}/svm_light/svm_hideo.c
${SVM_LIGHT_SRC_DIR}/svm_struct/svm_struct_learn.c
${SVM_LIGHT_SRC_DIR}/svm_struct/svm_struct_common.c
${SVM_LIGHT_SRC_DIR}/svm_struct/svm_struct_classify.c
${SVM_LIGHT_SRC_DIR}/svm_struct_api.c
${SVM_LIGHT_SRC_DIR}/svm_struct_learn_custom.c
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} svm_rank_lib)
Cmake configures fine it seems. Within the output of the configuration it specifies that it finds my C and C++ compilers and that they "work". I add the header to one of my project files using extern as follows:
#ifdef __cplusplus
extern "C" {
# include "svm_struct/svm_struct_common.h"
}
#endif
When I go to build my project the error is here:
../../Libraries/svm_rank/svm_struct/../svm_struct_api_types.h:75:11: error: expected member name or ';' after declaration specifiers
double *class; /* vector of scores that imply ranking */
~~~~~~ ^
1 error generated.
There is a variable within the library header called "class" where the error occurs, and my guess is that it's trying to compile this library header using C++ instead of C. First of all is this the reason for the error? If so, how should I go about fixing this?
As has already been pointed out, the source of the problem is that the C library header declares a variable named class, which is a keyword in C++.
This problem will hit you as soon as that header is pulled in by a C++ source file. Remember that headers are not compiled by themselves, but are merely copy-pasted by the preprocessor into the source file that #includes them. It is the type of the source file that determines whether the code in the header is interpreted as C or C++.
The fact that you wrapped the include in extern "C" does not change this. It simply switches off C++-style name mangling for the declarations in the header, but the code still has to compile as valid C++.
The cleanest solution to this problem is a technique known as insulation or compiler firewall.
You have to make sure that all parts that come into contact with the problematic library are C-source files themselves. The C++ part of your code only interacts with the library through the interface of that C part, but never with the library directly. In particular, you must never #include library headers from any of your header files.
For instance:
my_interface.c
#include "svm_struct/svm_struct_common.h" /* safe to include from a .c file */
struct opaque_ {
/* you can use types from svm_struct_common in here */
};
opaque* initialize()
{
/* you can create an opaque_ on the heap and
manipulate it here, as well as give a
pointer back to the C++ part */
}
void do_stuff(opaque*)
{
/* do whatever you like with the stuff in opaque */
}
my_interface.h
/* no #includes in the header! */
/* the opaque type is only forward declared!
C++ code can obtain a pointer to it,
but cannot look inside */
struct opaque_;
typedef struct opaque_ opaque;
opaque* initialize();
void do_stuff(opaque*);
my_application.cpp
// we only include our own header, which we made sure is valid C++
extern "C" {
#include <my_interface.h>
}
void do_stuff()
{
opaque* context = initialize();
do_stuff(context);
}
double *class; /* vector of scores that imply ranking */
class as highlighted in blue if it helps. Is a reserved word meaning you can't use it as a variable or macro name. Try changing it and it should remove the error.
Edit
I misunderstood you are compiling in C but it seems to compile in C++. But I still stand by my answer its best to change the variable class to keep the code compatible with C++ as class is a reserved word in C++.
I created a class and have some outside methods in a Functions.h header (think thats the problem). Anyway, when ever I try to use any type of C-style function in the class implementation file; even blank ones, I get a compiler/ liker error. I am new to this and don't understand what the problem is. I'm thinking I can't use the .h file, but I am able to use global vars and directives in the class file.
Where am I suppose to declare my outside functions? In what kind of file?
My guess is that you fully define the functions (including implementation) in a header file, and include that from multiple source files; and that the errors you forgot to describe say something about "multiple definitions" or "duplicate symbols":
// Header file
void some_function() {
// do some stuff
}
If that is the case, you need to either move the definitions into a source file, leaving just declarations in the header, so they only have a single definition:
// Header file
void some_function();
// Source file
void some_function() {
// do some stuff
}
or declare the definitions inline, which allows them to be included in more than one source file:
// Header file
inline void some_function() {
// do some stuff
}
If that isn't the problem, please post some example code and error messages so we don't have to guess what's happening.
You have c++ as a tag. Perhaps these functions are C++ functions but you're trying to get at them from an Obj-C file? If that's the case, you either need to turn them into C functions, or you need to use Obj-C++ (which has the .mm extension instead of .m).
Background
I have a project named PersonLibrary which has two files.
Person.h
Person.cpp
This library produces a static library file. Another project is TestProject which uses the PersonLibrary (Added though project dependencies in VS008). Everything worked fine until I added a non-member function to Person.h. Person.h looks like
class Person
{
public:
void SetName(const std::string name);
private:
std::string personName_;
};
void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
Person.cpp defines SetName function. When I try to use SetPersonName from TestProject, I get error LNK2005: already defined. Here is how I used it
#include "../PersonLibrary/Person.h"
int main(int argc, char* argv[])
{
Person person;
SetPersonName(person, "Bill");
return 0;
}
Workarounds tried
1 - I have removed the Person.cpp and defined the whole class in Person.h. Error gone and everything worked.
2 - Changed the SetPersonName modifier to static. Like the below
static void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
Questions
Why the code shown first is not working as I expected?
What difference static made here?
What is the approapriate solution for this problem?
Thanks
You either have to
move SetPersonName's definition to a .cpp file, compile and link to the resulting target
make SetPersonName inline
This is a well known case of One Definition Rule violation.
The static keyword makes the function's linkage internal i.e. only available to the translation unit it is included in. This however is hiding the real problem. I'd suggest move the definition of the function to its own implementation file but keep the declaration in the header.
When you compile you're library, its lib file contains a definition for SetPersonName. When you compile your program that uses the library, since it includes the header, and you've written the code inline in the header it also compiles in a definition for SetPersonName. Two definitions for the same function aren't (generally) allowed. The static keyword tells the compiler that the function shouldn't be exposed outside of the current translation unit (discrete piece of code you are compiling), so the definition in the library isn't visible to the linker.
The appropriate solution to this problem depends on your goals. Header files with static function declarations is almost never what you want. From a design standpoint I would recommend getting rid of SetPersonName altogether, and just use Person::SetName.
However, failing that, I would implement it much like you've done for the rest of your functionality, declarations in the header, and implementation in the .cpp. Inline functions associated with a library will tend to diminish many of the advantages of using a library in the first place.
By declaring the function static you are scoping it to the current translation unit, so in effect you have added a new SetPersonName function in your main file, and would be calling that not the one defined in the library.
The correct solution is to declare SetPersonName as extern in person.h and implement it in person.cpp
Person.h
extern void SetPersonName(Person& person,const std::string name);
Person.cpp
void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
The function SetPersonName will be compiled into each objectfile that includes the Person.h file, thus making the linker seeing several functions and giving the error.
By writing static you state that the function will only be visible within a single objectfile. You will still get several functions in you binary but now you will not get the errors.
Try to write inline before the function like
inline void SetPersonName(Person& person,const std::string name)
{
person.SetName(name);
}
...because the function is pretty simple it is OK I think to have it as an inline. An inline will place the necessary code where the function is used, without actually creating a function to be called.
A solution would be to make that function a static method. That will stop the "already defined" errors.
I had a similar situation as described clearly by #logan-capaldo above.
A CPP source file (myfile.cpp) contained a function MyFunction. When building, this got compiled into myfile.obj. But the main CPP file (main.cpp) also included myfile.cpp, so the function MyFunction was being included/compiled/linked twice, leading to the "LNK2005 already defined" error.
This is messy but I didn't have time to fix it properly. The quickest fix (in VS Express 2012) was to right-click myfile.cpp in Solution Explorer, go to Properties and change Excluded From Build to Yes. I guess this prevents one of the OBJ files from being created and/or linked and so removes the error.
For anyone landing here dealing with this error in a Qt project, make sure you don't have any non-signal functions defined under signals: in your header files.
Incorrect, throws LNK2005 on Foo::promiseData():
class Foo : public QObject {
Q_OBJECT
public:
explicit Foo(QObject* parent = nullptr);
signals:
void dataReady(QList<QObject*> data) const;
void promiseData() const; // <-- This function is not supposed to be a signal.
Correct:
class Foo : public QObject {
Q_OBJECT
public:
explicit Foo(QObject* parent = nullptr);
void promiseData() const;
signals:
void dataReady(QList<QObject*> data) const;