Thread: Splitting source into multiple files(Linux & make)

  1. #1
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477

    Splitting source into multiple files(Linux & make)

    I consider myself to be a pretty able programmer, for a hobbyist, but I've run into some problems that I cannot seem to solve.
    I'm taking my first shot at any real linux programming, and I am writing an ircbot for a channel I frequent. The linuxy part of it will be its eventual ability to use modules to call user-defined functions on certain events(E.g. receives PRIVMSG and it checks the PRIVMSG event chain. If someone has registered, it'll call the function in that module.. ).. I digress.

    The problem I'm having is that, after the initial stages where it was all bunched up in one source file(Should have started out the other way), I decided to divide it all up into multiple source files. This has never really been a problem for me - I've done this plenty of times on Visual Studio, but the difference is that I'm not using an IDE that does the work for me, and I'm using make.

    I'll describe the files:

    ircbot.c: Contains the main function, which call various functions from botfunctions.c
    botfunctions.c: Contains definitions for functions.
    prototypes.h: Prototypes for functions in botfunctions.c
    botstructs.h: Contains definitions for various structures used to structure input and so on.

    What I started by doing is what I've done in most of my other projects. I use a main "includes.h" file which contains all the standard header files(stdio.h, network header files and all that), and includes the other header files, like prototypes, botstructs and so on. I then include this file in the other source files.

    Thing is, if I use make, I can get everything to compile, since it splits everything into object files. ircbot.c compiles to ircbot.o fine, and botfunctions.c to botfunctions.o too, and they are compiled into the main executable fine. If I run this executable, however, I get the output I'm supposed to see a billion times over. In fact, it is too much for my terminal to handle and I have to manually kill it. The bot functions properly past that - it connects and does what it's supposed to do, only once, not a billion times like when it displays output.
    Looking at the disassembly of the executable, it looks like main is a series of conditional jumps into itself.

    I know there's something wrong here, since if I just try to compile with gcc, it doesn't like it and gives me undefined references to all the functions, in spite of the prototypes.h file being included.

    Can someone give me some tips on this? I have read several makefile tutorials and "split your project into many files"-tutorials, but none of the mention strange cyclic calling errors(Cyclic dependencies, but not strange loops).

    I would really appreciate it if someone could give me some hints on what I'm doing wrong, and tips for the future. Is the "one main include file with include guard"-approach no good? If so, why not?

    Much appreciated,
    IceDane
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    What does your makefile look like (roughly, if it's too big to post here)?

    You should have something like
    Code:
    bot : all your o files here
            gcc -o bot all your o files here again
    (where naturally you'd use $variables for most of that). On the other hand, I'm not sure what you're doing differently that you can't compile the thing by hand....

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Technically for Windows, but uses gmake, which is the same make-program as Linux uses, here is the makefile for Minibasic. It's not a VERY complex, but it's not simple either.
    matsp / minibasic / source — bitbucket.org

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by IceDane
    Thing is, if I use make, I can get everything to compile, since it splits everything into object files. ircbot.c compiles to ircbot.o fine, and botfunctions.c to botfunctions.o too, and they are compiled into the main executable fine. If I run this executable, however, I get the output I'm supposed to see a billion times over. In fact, it is too much for my terminal to handle and I have to manually kill it. The bot functions properly past that - it connects and does what it's supposed to do, only once, not a billion times like when it displays output.
    Looking at the disassembly of the executable, it looks like main is a series of conditional jumps into itself.
    Perhaps this is just a major bug with your program and is unrelated to your makefile.

    Quote Originally Posted by IceDane
    I know there's something wrong here, since if I just try to compile with gcc, it doesn't like it and gives me undefined references to all the functions, in spite of the prototypes.h file being included.
    Whether you automate the process or run the commands manually, you still need to link the object files together to form the executable program. That a common header is included everywhere is orthogonal to this.

    Quote Originally Posted by IceDane
    Is the "one main include file with include guard"-approach no good? If so, why not?
    I presume that each header file has its own include guard as well?

    One problem with having a common "mother of all headers" that includes all the other headers is that a change to any header will then require much more re-compilation than is necessary. If each source file and header only included those headers that are necessary (or none at all, if forward declarations will suffice), then a change to one header would only require re-compilation of those source files that include it.

    However, the use of pre-compiled headers should be able to alleviate this problem, and a common header can simplify things for a user of your library, should you be providing one.

    A related problem is that it becomes harder to separate parts of what you have written for reuse in another program since each source file would depend on all the headers.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Quote Originally Posted by tabstop View Post
    What does your makefile look like (roughly, if it's too big to post here)?

    You should have something like
    Code:
    bot : all your o files here
            gcc -o bot all your o files here again
    (where naturally you'd use $variables for most of that). On the other hand, I'm not sure what you're doing differently that you can't compile the thing by hand....
    Thanks for the reply.

    My makefile is as follows:

    Code:
    ircbot:  ircbot.o botfunctions.o
    	gcc -Wall -ggdb3 ircbot.o botfunctions.o -o ircbot
    
    ircbot.o: ircbot.c
    	gcc -Wall ircbot.c -c
    	
    botfunctions.o: botfunctions.c
    	gcc -Wall botfunctions.c -c
    
    clean:
    	rm -rf *.o
    That does compile(if I used the main include file approach), too, like I said, but that gives me the strange errors I mentioned.

    Do I have to use extern or some such? I have never ever had to use that keyword(I haven't been using global variables much) and everything has worked fine, so I know this can be done without using extern.

    EDIT: laserlight: The program compiled and ran as per expectations before I split it up.
    Last edited by IceDane; 05-18-2009 at 06:25 AM.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  6. #6
    Ex scientia vera
    Join Date
    Sep 2007
    Posts
    477
    Sorry - this seems to be a bug with my program anyway. The input is printed way too often for some bizarre reason, but it works after that. I simply thought this was an effect of splitting it up(Even in spite of that conclusion going against my instinct), but now that I've put everything as it was(in one file), I still get the same strange error.

    Thanks for trying to help me solve an error that wasn't there anyway, though, heh.
    "What's up, Doc?"
    "'Up' is a relative concept. It has no intrinsic value."

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,412
    Quote Originally Posted by IceDane
    but now that I've put everything as it was(in one file), I still get the same strange error.

    Thanks for trying to help me solve an error that wasn't there anyway, though, heh.
    Haha, but good to know we had the same instincts about the problem and it turned out to be correct

    What you can do now is to take a diff between your newly re-combined source and the one that worked. Chances are, the bug was introduced in the changed portions (but it could also have been latent in the unchanged portions, then "triggered" when you made other changes).
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multiple Read File Descriptors
    By blue8173 in forum C Programming
    Replies: 9
    Last Post: 04-21-2004, 01:19 PM
  2. Multiple Source Files!?!?
    By Padawan in forum C Programming
    Replies: 14
    Last Post: 04-04-2004, 12:19 AM
  3. Linking multiple source files: Undefiled Reference to...
    By Inquirer in forum C++ Programming
    Replies: 4
    Last Post: 05-03-2003, 05:47 PM
  4. Replies: 1
    Last Post: 05-01-2003, 02:52 PM
  5. using a class in multiple source files???
    By Crossbow in forum C++ Programming
    Replies: 9
    Last Post: 06-18-2002, 07:42 PM