Xcode, Duplicate symbol error during compilation? (C)

In summary: NewEntry in /Users/.../main.o and /Users/.../myFunctions.o for architecture x86_64collect2: ld returned 1 exit status ...as a way of saying "I give up - you can't have two functions with the same name".One more thing - you're calling fpurge() to clear the input buffer. This is not a good idea. It's a non-standard function, and it's not present on other operating systems. It may also have other unexpected side-effects. It's more usual to call scanf() like this...scanf("%5s%*[^\n]", userInput); ...which will consume up to five characters of user input.
  • #1
Epic Sandwich
25
0
I'm following a tutorial off of the internet - http://masters-of-the-void.com/book10.htm" [Broken] one to be exact - and whenever I try and compile I get this error:

[PLAIN]http://dl.dropbox.com/u/1426380/Screen%20shot%202010-08-01%20at%2015.26.11.png [Broken]

I've tried going over my code again and again, but seeing as it doesn't seem to tell me where the error is happening, it's really difficult for me (as a beginner with C) to actually find the problem.

I'll post all my code below to help you out.

main.c:
Code:
#include "main.h"
#include "myFunctions.c"

int numDatabaseEntries = 0;
struct DatabaseEntry * gDatabase = NULL;

int		main()			//Main program function
{
	
	bool keepRunning = true;	//Declares and assigns variable to allow program to loop
	char userInput[11];			//String for user input
	
	printf("Welcome to the CD Database!\n");	//Welcome message. Only displayed once as it is outside of the 'while' block
	
	while ( keepRunning == true )	//Keeps program looping while the keepRunning variable is true
	{
		printf( "\nType NEW, LIST, CLEAN or QUIT:\n>" );
		scanf( "%5s", userInput );
		fpurge( stdin );
		
		if ( strcmp( userInput, "NEW" ) == 0 )
			NewEntry();			//Code for new database entry
		else if ( strcmp( userInput, "LIST" ) == 0 )
			List();				//Code for list database
		else if ( strcmp( userInput, "CLEAN" ) == 0 )
			CleanUp();			//Code for cleanup
		else if( strcmp( userInput, "QUIT" ) == 0 )
		{
			keepRunning = false;						//Ends program by exiting out of the loop
			CleanUp();									//Frees memory before quitting
		}
		else
			printf( "Error, command '%s' is unknown.", userInput );	//Prints unknown command to warn user
		
	}
	
	printf("\nThank you for using the CD Database.");
	
	return 0;					//Returns ok value to OS
}

myFunctions.c:
Code:
#include "main.h"

struct DatabaseEntry	//Defines custom data structure to use to store information on each CD
{
	char	artist[40];
	char	composer[40];
	char	albumName[40];
	int		trackCount;
	bool	isSampler;
	
};

void	NewEntry()		//Function used for entering a new entry to database
{
	char yesOrNo;		//For 'is sampler' later on
	
	//Create new array element, or new array if no array exists
	if ( gDatabase == NULL )
	{
		gDatabase = malloc( sizeof(struct DatabaseEntry) );
		if ( gDatabase == NULL )		//Still null? Error must have occured
		{
			printf( "Error, couldn't create a new entry.\n" );
			return;
		}
	}
	else 
	{
		struct DatabaseEntry * newPtr = NULL;	//Declare temporary Database holder to use realloc with
		newPtr = realloc( gDatabase, ( numDatabaseEntries + 1 ) * sizeof( struct DatabaseEntry ) );	//Make newPtr one unit bigger than old database, shove everything in it
		if ( newPtr == NULL )	//Out of memory?
		{
			printf( "Error, couldn't create a new entry.\n" );
			return;				//Keeps gDatabase as old pointer
		}
		
		gDatabase = newPtr;		//Copy all of newPtr back into gDatabase, make gDatabase main database again.
	}
	
	numDatabaseEntries += 1;		//Increase database entries by 1;
	
	//Allow user to input data and store it in the database
	printf( "\nArtist name: " );
	scanf( "%39s", gDatabase[ numDatabaseEntries - 1 ].artist );
	fpurge( stdin );
	
	printf( "Composer: " );
	scanf( "%39s", gDatabase[ numDatabaseEntries - 1 ].composer );
	fpurge( stdin );
	
	printf( "Album name: " );
	scanf( "%39s", gDatabase[ numDatabaseEntries - 1 ].albumName );
	fpurge( stdin );
	
	printf ("Track count: " );
	scanf( "%d", &gDatabase[ numDatabaseEntries -1 ].trackCount );
	fpurge( stdin );
	
	printf( "Sampler? (y/n): " );
	scanf( "%c", &yesOrNo );
	fpurge( stdin );
	
	gDatabase[ numDatabaseEntries - 1 ].isSampler = false;										//Assigns it as false initially
	gDatabase[ numDatabaseEntries - 1 ].isSampler = ( yesOrNo == 'y' || yesOrNo == 'Y' );		//Assigns it as true if Y or y is inputed
	
}

void	List()			//Function to list CDs
{
	if ( gDatabase == NULL )
	{
		printf( "There are no CDs in the database!" );
		return;
	}
	
	for ( int x = 0; x < numDatabaseEntries; ++x )
	{
		printf( "\nArtist name: %s\n", gDatabase[ x ].artist );
		printf( "Composer: %s\n", gDatabase[ x ].composer );
		printf( "Album name: %s\n", gDatabase[ x ].albumName );
		printf( "No. of tracks: %d\n", gDatabase[ x ].trackCount );
		if ( gDatabase[ x ].isSampler )
			printf( "This CD is a sampler\n" );
	}
	
}

void	CleanUp()		//Function to free memory
{
	if ( gDatabase != NULL )
	{
		free( gDatabase );
		gDatabase = NULL;
		numDatabaseEntries = 0;
	}
	
}

main.h:
Code:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

struct DatabaseEntry;

//Defines custom data structure to use to store information on each CD

int numDatabaseEntries;
struct DatabaseEntry * gDatabase;

void NewEntry();
void List();
void CleanUp();

I think it's something to do with the data structure not being declared properly, I've tried doing different things with it but none of them have got rid of the error.

I apologise if I've done something completely wrong here, the lesson that I was following was a bit vague at times, and i wasn't that sure on where to put things in terms of header files etc.

Thanks.
 
Last edited by a moderator:
Technology news on Phys.org
  • #2
Lovely helpful IDE you have there...

Did you try clicking on the ...more... in that error line to see if it can provide more? Like which file and line number is causing it to choke?

At first glance your code looks fine. If you can't get any more help from your IDE I would start changing names and moving code around to see if I could have any effect on the problem.
 
  • #3
The first error shown is a linker error, showing a duplicate symbol for _NewEntry. It's likely that gcc already has a variable or function or something with this name. I would change the name of the NewEntry function to eliminate this linker error. Something like New_Entry would probably work, or NewSongEntry, or ?
 
  • #4
Just tried changing the name of NewEntry numerous times, but it had no effect. The exact same error came up.

Also, I tried making a new project and copying all the code over, just to see if XCode had done something messy when I was experimenting with headers. But the same error still came up.

For schip666!, here's the complete error message. It is rather vague to be honest:

[PLAIN]http://dl.dropbox.com/u/1426380/Screen%20shot%202010-08-02%20at%2021.09.21.png [Broken]

I'm really confused as to why this is happening, there must be a reason for it, surely?
 
Last edited by a moderator:
  • #5
If you declare a boolean variable as TRUE is it then a static variable? If so you can't change it in the program to FALSE.
Try using 'BOOL keeprunning;' without assigning a value.
 
  • #6
In main.c, you have a preprocessor directive where you're including myFunctions.c. Take that line out. You should never #include a C source file - only .h header files.

I think this is where your problem lies - the compiler is being fooled into thinking there are two definitions for GetEntry(). I'm guessing that it also thinks there are two definitions for List() and Cleanup() as well, but the linker is probably choking on the first of these, and giving up.
 
  • #7
Mark44 said:
In main.c, you have a preprocessor directive where you're including myFunctions.c. Take that line out. You should never #include a C source file - only .h header files.

I think this is where your problem lies - the compiler is being fooled into thinking there are two definitions for GetEntry(). I'm guessing that it also thinks there are two definitions for List() and Cleanup() as well, but the linker is probably choking on the first of these, and giving up.

Yep, you got it. I thought that you had to include the .c file to let the compiler know about the contents (in the case, the functions it contains), so this isn't the case? All you have to do is have it in the source folder?
 
  • #8
In the old days you had to specify things explicitly in a makefile. Now your IDE knows what to build. Never, ever, ever #include a .c file. It is legal to do so only because the C preprocessor is incredibly stupid. It also almost always very bad form.
 
  • #9
D H said:
In the old days you had to specify things explicitly in a makefile. Now your IDE knows what to build. Never, ever, ever #include a .c file. It is legal to do so only because the C preprocessor is incredibly stupid. It also almost always very bad form.

Ok, I'll keep that in mind.

Briefly, could you sum up what I should use .h files for and what I should use .c files for? I'm a bit confused at the moment.
 
  • #10
Use .h files for function prototypes, struct template definitions, and global constants. Use .c files for function definitions (i.e., where you actually define how the functions work as opposed to their signatures). That should roughly cover the division of what goes where.
 
  • #11
The problem with using an integrated IDE like Xcode for introductory level programming is that it obscures the stages of the compilation/linking process, which are the key to why .c and .h files exist.

To summarize what you might have read or heard already, when you compile a program you actually do two things:

(1) You compile the source code into machine code. Each function produces a chunk of machine code.

(2) You link the chunks of compiled machine code from your source code, with other chunks of machine code from system libraries, to produce the complete executable program.

Basically, a .c file contains code for functions that are compiled separately from the rest of the program. A .h file "tells" other .c files how the functions in the separately-compiled .c file are supposed to be called.

Here's an example, starting with a simple complete program with a few functions, in a single file. It's C++ because that's what I'm familiar with, but the basic program structure is the same as in C. Instead of .c files I use .cpp files.

Code:
// lorentz.cpp - main function and sub-functions together as a
// complete program

#include <iostream>
#include <cmath>

using namespace std;

double lorentz_gamma (double v)
{
    const double c = 3e8;
    return 1.0 / sqrt (1 - (v*v)/(c*c));
}

double lorentz_xprime (double x, double t, double v)
{
    return lorentz_gamma(v) * (x - v*t);
}

double lorentz_tprime (double x, double t, double v)
{
    const double c = 3e8;
    return lorentz_gamma(v) * (t - v*x/(c*c));
}

int main ()
{
    cout << "Lorentz transformation calculator" << endl;
    cout << "Enter x, t and v: ";
    double x, t, v;
    cin >> x >> t >> v;
    cout << "The transformed x and t are "
         << lorentz_xprime(x, t, v) << " " 
         << lorentz_tprime(x, t, v) << endl;
    return 0;
}

Here's how I compile, link and run it at the Unix command line, in a Terminal window under Mac OS:

Code:
$ g++ lorentz.cpp -o lorentz
$ ./lorentz
Lorentz transformation calculator
Enter x, t and v: 0 1 2e8
The transformed x and t are -2.68328e+08 1.34164
Jons-Mac-Pro:lorentz jtbell$

Now I decide that I want to split the functions into a separate file so I can use them in other programs. Further, I want to compile them only once, and then link the compiled code into other programs as necessary. (If these were large functions, this could save a significant amount of compilation time.)

So I move the functions into a separate file:

Code:
// lorentz_subs.cpp - functions for calculating 
// the Lorentz transformation

double lorentz_gamma (double v)
{
    const double c = 3e8;
    return 1.0 / sqrt (1 - (v*v)/(c*c));
}

double lorentz_xprime (double x, double t, double v)
{
    return lorentz_gamma(v) * (x - v*t);
}

double lorentz_tprime (double x, double t, double v)
{
    const double c = 3e8;
    return lorentz_gamma(v) * (t - v*x/(c*c));
}

I try compiling it separately, without linking it to anything else. The "-c" switch in the "g++" command means "compile only".

Code:
$ g++ lorentz_subs.cpp -c
lorentz_subs.cpp: In function 'double lorentz_gamma(double)':
lorentz_subs.cpp:4: error: 'sqrt' was not declared in this scope
$

Oops, I need to declare sqrt(), so I add an include statement for the header file that contains the declarations of the math functions. ("math.h" in C corresponds to "cmath" in C++.)

Code:
// lorentz_subs.cpp - functions for calculating 
// the Lorentz transformation

#include <cmath>

double lorentz_gamma (double v)
{
    const double c = 3e8;
    return 1.0 / sqrt (1 - (v*v)/(c*c));
}

double lorentz_xprime (double x, double t, double v)
{
    return lorentz_gamma(v) * (x - v*t);
}

double lorentz_tprime (double x, double t, double v)
{
    const double c = 3e8;
    return lorentz_gamma(v) * (t - v*x/(c*c));
}

Now it compiles successfully:

Code:
$ g++ lorentz_subs.cpp -c
$

I now have a file named lorentz_subs.o which contains the compiled code for these functions.

Now I turn to the main program. I delete the functions and rename the file :

Code:
// lorentz_main.cpp - main program only

#include <iostream>

using namespace std;

int main ()
{
    cout << "Lorentz transformation calculator" << endl;
    cout << "Enter x, t and v: ";
    double x, t, v;
    cin >> x >> t >> v;
    cout << "The transformed x and t are "
         << lorentz_xprime(x, t, v) << " " << lorentz_tprime(x, t, v) << endl;
    return 0;
}

I removed the #include <cmath> because this file no longer uses any of the math functions directly. I try to compile it, again without linking:

Code:
$ g++ lorentz_main.cpp -c
lorentz_main.cpp: In function 'int main()':
lorentz_main.cpp:12: error: 'lorentz_xprime' was not declared in this scope
lorentz_main.cpp:12: error: 'lorentz_tprime' was not declared in this scope
$

I need to declare the two functions that I removed. One way is to insert prototypes that indicate the return type, and the types of the arguments. This allows the compiler to check that I'm calling the functions properly.

Code:
// lorentz_main.cpp - main program only

#include <iostream>

using namespace std;

double lorentz_xprime (double x, double t, double v);
double lorentz_tprime (double x, double t, double v);

int main ()
{
    cout << "Lorentz transformation calculator" << endl;
    cout << "Enter x, t and v: ";
    double x, t, v;
    cin >> x >> t >> v;
    cout << "The transformed x and t are "
         << lorentz_xprime(x, t, v) << " " << lorentz_tprime(x, t, v) << endl;
    return 0;
}

Compile it:

Code:
$ g++ lorentz_main.cpp -c
$

It works! Now I have a file named lorentz_main.o, and I can link the two separately-compiled parts of the program and run it:

Code:
$ g++ lorentz_main.o lorentz_subs.o -o lorentz
$ ./lorentz
Lorentz transformation calculator
Enter x, t and v: 0 1 2e8
The transformed x and t are -2.68328e+08 1.34164
$

But it's a nuisance, having to write out the prototypes for those functions every time I write a program that uses them. So I put them into a separate file, lorentz_subs.h, and "include" that file when necessary. The preprocessor in effect "pastes" those prototypes into whatever file contains the "include" directive. So now I have this:

Code:
// lorentz_subs.h - prototypes for Lorentz transformation functions

double lorentz_gamma (double v);
double lorentz_xprime (double x, double t, double v);
double lorentz_tprime (double x, double t, double v);

(I added a prototype for lorentz_gamma() in case I might want to use it in some other program.)

Code:
// lorentz_main.cpp - main program only

#include <iostream>
#include "lorentz_subs.h"

using namespace std;

int main ()
{
    cout << "Lorentz transformation calculator" << endl;
    cout << "Enter x, t and v: ";
    double x, t, v;
    cin >> x >> t >> v;
    cout << "The transformed x and t are "
         << lorentz_xprime(x, t, v) << " " << lorentz_tprime(x, t, v) << endl;
    return 0;
}

I can compile these files together with lorentz_subs.cpp either one step at a time:

Code:
$ g++ lorentz_subs.cpp -c
$ g++ lorentz_main.cpp -c
$ g++ lorentz_main.o lorentz_subs.o -o lorentz
$

Or if I already have lorentz_subs.o lying around, I just need to compile lorentz_main.cpp, and link it:

Code:
$ g++ lorentz_main.cpp lorentz_subs.o -o lorentz
$

Or I can compile and link everything in one go:

Code:
$ g++ lorentz_main.cpp lorentz_subs.cpp -o lorentz
$
 
Last edited:
  • #12
Whoa...great catch on that #include... I guess the linker just complained about the first duplicate and gave up. Moving the functions around in the file would have given a further clue, which might not have been any clearer...

In looking more carefully I notice that you have declarations in both main.h and main.c:

struct DatabaseEntry;

//Defines custom data structure to use to store information on each CD

int numDatabaseEntries;
struct DatabaseEntry * gDatabase;

First, I think you should move your DatabaseEntry struct definition from myFunctions.c to main.h because the empty definition now in main.h may cause you trouble.

Second, your compiler may be smart enough to know that numDatabaseEntries and gDatabase are the same entity but I would put "extern" in front of them in the header file to avoid ambiguities.

All that said, I learned C before there was an ANSI so I probably haven't kept current on all the standard features and restrictions. If it works, use it...
 
  • #13
Wow, awesome last few posts here. I've just learned a ton, thanks everyone :biggrin:
 
  • #14
Just a wild guess here, but wondering if you changed the declartion and actual function to:

void NewEntry(void);

if this would help. Perhaps the compiler is making conflicting definitions for NewEntry(..) in the case where it's only used (main.c) versus where its defined (myfunctions.c).
 
Last edited:

1. What is Xcode?

Xcode is an integrated development environment (IDE) created by Apple for building apps for iOS, macOS, watchOS, and tvOS. It includes a suite of tools and features for writing, debugging, and deploying code.

2. What does the Duplicate symbol error mean in Xcode?

The Duplicate symbol error occurs when there are two or more objects with the same name in your project. This can happen if you accidentally create two classes with the same name or if you import a library that contains a class with a name that already exists in your project.

3. How can I fix the Duplicate symbol error in Xcode?

To fix this error, you will need to find the duplicate symbol and remove it from your project. This could involve renaming a class, removing a duplicate library, or using namespaces to differentiate between similar objects.

4. Can Xcode automatically resolve Duplicate symbol errors?

No, Xcode cannot automatically resolve Duplicate symbol errors. You will need to manually fix the issue by identifying and removing the duplicate symbol.

5. How can I prevent Duplicate symbol errors in Xcode?

To prevent Duplicate symbol errors, it is important to carefully name your classes, variables, and functions to avoid any potential conflicts. You should also avoid importing libraries that contain objects with the same name as ones in your project.

Similar threads

  • Engineering and Comp Sci Homework Help
Replies
1
Views
8K
  • Programming and Computer Science
Replies
4
Views
2K
  • Programming and Computer Science
Replies
5
Views
1K
  • Programming and Computer Science
Replies
22
Views
5K
  • Programming and Computer Science
Replies
2
Views
3K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
3K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
12
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
1K
Back
Top