0

I am trying to build a project using CMake that has the following directory structure Simple folder structure

This is the code for the root CMakeLists.txt

include_directories(Steganos PUBLIC ${PROJECT_SOURCE_DIR}/src)

add_executable (
    Random_Project_name
    ${PROJECT_SOURCE_DIR}/src/general/main.cpp
)


add_subdirectory(src/modules/image)
target_link_libraries(Steganos IMAGE_MODULES)

and this is the code for the second CMakeLists.txt stored in src/modules/image:



add_library(
    BMP_MODULE OBJECT
    "bmp.h"
    "bmp/bmp_module.cpp"
    "bmp/bmp_decoder.cpp"
    "bmp/bmp_encoder.cpp"
)

add_library(
    IMAGE_MODULES
    $<TARGET_OBJECTS:BMP_MODULE>
)

In bmp.h i have 3 classes declared that i am defining in bmp_decoder/bmp_encoder/bmp_module.cpp and those just include bmp.h

This is the code for bmp.h

#pragma once

#include "general/module.h"

class BMPModule : protected Module {
protected:
    //protected functions and variables
public:
    BMPModule(const char* bmp_file_path);
    ~BMPModule();

    //public functions
};

class BMPEncoderModule : public BMPModule {
private:
    //private variables
public:
    BMPEncoderModule(const char* cover_file_path, const char* secret_file_path) : BMPModule(cover_file_path) {
        //other initialization
        utils::read_byte_stream(/* necessary parameters */);
    }
    ~BMPEncoderModule();

    //public functions
};

class BMPDecoderModule : protected BMPModule {
private:
    //private variables and functions
public:
    BMPDecoderModule(const char* embedded_path) : BMPModule(embedded_path) {
        //other initialization
        utils::read_byte_stream(/* necessary parameters */);
    }
    ~BMPDecoderModule();
    //public functions 
};

and this is the code for utils.h

#pragma once

#include <fstream>

enum class error_code {
    //random error codes describing what went wrong
};

namespace utils {
    //given a pointer to a stream opened in binary mode and a pointer for a byte array,
    //reads the byte array and returns how many bytes were read
    error_code read_byte_stream(std::ifstream* stream, uint8_t* &byte_stream, uint32_t& stream_size) {
        return 1337;
    }
}

Well my problem is when i try to build the project i get a linker error telling me that read_byte_stream is already defined in main.cpp.obj

Error   LNK2005 "enum error_code __cdecl utils::read_byte_stream(class std::basic_ifstream<char,struct std::char_traits<char> > *,unsigned char * &,unsigned int &)" (?read_byte_stream@utils@@YA?AW4error_code@@PEAV?$basic_ifstream@DU?$char_traits@D@std@@@std@@AEAPEAEAEAI@Z) already defined in main.cpp.obj   ${OUT_FOLDER} ${OUT_FOLDER}\IMAGE_MODULES.lib(bmp_module.cpp.obj)   

What am i doing wrong? Should i only have one file associated to bmp.h?(and not 3?) The project builds and runs well if i add inline to read_byte_stream function. Thank you in advance!

  • 1
    Most likely this is a dupe of [this](https://stackoverflow.com/questions/249701/why-arent-my-compile-guards-preventing-multiple-definition-inclusions) but I can't say for certain without seeing a [mre] – NathanOliver Feb 26 '20 at 21:17
  • Provided `utils.h` is included in more than 1 translation unit (source file) your bug is in `utils.h` you can't define the functions in the header. Define them in `utils.cpp`. The link @NathanOliver posted should be a duplicate. – drescherjm Feb 26 '20 at 21:32
  • Thank you @NathanOliver and drescherjm , i messed up by defining my functions in the header file. Adding a file utils.cpp for the definitions fixed the issue – Stefan Pricope Feb 27 '20 at 11:03
  • You could also do what Alan said in his answer. – drescherjm Feb 27 '20 at 13:25

1 Answers1

0

When defining functions (or methods) in header files you should mark them as inline so that the linker ignores duplicate copies in multiple translation units:

namespace utils {
    //given a pointer to a stream opened in binary mode and a pointer for a byte array,
    //reads the byte array and returns how many bytes were read
    inline error_code read_byte_stream(std::ifstream* stream, uint8_t* &byte_stream, uint32_t& stream_size) {
        return 1337;
    }
}
drescherjm
  • 10,365
  • 5
  • 44
  • 64
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60