Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Include issue: 'multiple definition', 'first defined here'

Tags:

c++

I have three files:

main.cpp
MyClass.cpp
MyClass.hpp

I have a library header file, "testLib.hpp", that I want to include in MyClass.hpp so that I can have one of testLib's objects be a class attribute.

I include MyClass.hpp in MyClass.cpp and in main.cpp. When attempting to compile the project, I get the following errors

MyClass.cpp   multiple definition of 'testLib::testLib::function1()
obj/Release/main.o:main.cpp first defined here
MyClass.cpp   multiple definition of 'testLib::testLib::function2()
obj/Release/main.o:main.cpp first defined here

and so on.

Both main.cpp and MyClass.cpp include MyClass.hpp (which includes testLib.hpp). Judging by the error, it looks like MyClass.cpp is attempting to include the library functions after they've already been included by main.cpp. However, I have include guards present in MyClass.hpp so I don't understand how it's trying to include MyClass.hpp twice.

Here's the code:

MyClass.hpp

#ifndef THIS_HEADER_H
#define THIS_HEADER_H

#include <stdint.h>
#include <iostream>
#include "testLib/testLib.hpp"

class MyClass
{

public:
    void test();
    int foo;

private:
    uint32_t bar;
    //I want to include an object from the library as part of this class
    //TestLib::Device device;
};

#endif

MyClass.cpp

#include <stdio.h>
#include "MyClass.hpp"

void MyClass::test()
{

}

main.cpp

#include <iostream>
#include "MyClass.hpp"

using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    return 0;
}

Any help would be greatly appreciated!

EDIT I tried to hide the actual filenames to make the question more general and clear, but it seems like the problem might be resulting from 'testLib.hpp', which I did not write. That file is actually the following "sweep.hpp" file. I got the 'multiple definition of/first defined here' errors for each of the public functions in this file:

sweep.hpp

#ifndef SWEEP_DC649F4E94D3_HPP
#define SWEEP_DC649F4E94D3_HPP

/*
 * C++ Wrapper around the low-level primitives.
 * Automatically handles resource management.
 *
 * sweep::sweep  - device to interact with
 * sweep::scan   - a full scan returned by the device
 * sweep::sample - a single sample in a full scan
 *
 * On error sweep::device_error gets thrown.
 */

#include <cstdint>
#include <memory>
#include <stdexcept>
#include <vector>

#include <sweep/sweep.h>

namespace sweep {

// Error reporting

struct device_error final : std::runtime_error {
  using base = std::runtime_error;
  using base::base;
};

// Interface

struct sample {
  const std::int32_t angle;
  const std::int32_t distance;
  const std::int32_t signal_strength;
};

struct scan {
  std::vector<sample> samples;
};

class sweep {
public:
  sweep(const char* port);
  sweep(const char* port, std::int32_t bitrate);
  void start_scanning();
  void stop_scanning();
  bool get_motor_ready();
  std::int32_t get_motor_speed();
  void set_motor_speed(std::int32_t speed);
  std::int32_t get_sample_rate();
  void set_sample_rate(std::int32_t speed);
  scan get_scan();
  void reset();

private:
  std::unique_ptr<::sweep_device, decltype(&::sweep_device_destruct)> device;
};

// Implementation

namespace detail {
struct error_to_exception {
  operator ::sweep_error_s*() { return &error; }

  ~error_to_exception() noexcept(false) {
    if (error) {
      device_error e{::sweep_error_message(error)};
      ::sweep_error_destruct(error);
      throw e;
    }
  }

  ::sweep_error_s error = nullptr;
};
}

sweep::sweep(const char* port)
    : device{::sweep_device_construct_simple(port, detail::error_to_exception{}), &::sweep_device_destruct} {}

sweep::sweep(const char* port, std::int32_t bitrate)
    : device{::sweep_device_construct(port, bitrate, detail::error_to_exception{}), &::sweep_device_destruct} {}

void sweep::start_scanning() { ::sweep_device_start_scanning(device.get(), detail::error_to_exception{}); }

void sweep::stop_scanning() { ::sweep_device_stop_scanning(device.get(), detail::error_to_exception{}); }

bool sweep::get_motor_ready() { return ::sweep_device_get_motor_ready(device.get(), detail::error_to_exception{}); }

std::int32_t sweep::get_motor_speed() { return ::sweep_device_get_motor_speed(device.get(), detail::error_to_exception{}); }

void sweep::set_motor_speed(std::int32_t speed) {
  ::sweep_device_set_motor_speed(device.get(), speed, detail::error_to_exception{});
}

std::int32_t sweep::get_sample_rate() { return ::sweep_device_get_sample_rate(device.get(), detail::error_to_exception{}); }

void sweep::set_sample_rate(std::int32_t rate) {
  ::sweep_device_set_sample_rate(device.get(), rate, detail::error_to_exception{});
}

scan sweep::get_scan() {
  using scan_owner = std::unique_ptr<::sweep_scan, decltype(&::sweep_scan_destruct)>;

  scan_owner releasing_scan{::sweep_device_get_scan(device.get(), detail::error_to_exception{}), &::sweep_scan_destruct};

  auto num_samples = ::sweep_scan_get_number_of_samples(releasing_scan.get());

  scan result;
  result.samples.reserve(num_samples);

  for (std::int32_t n = 0; n < num_samples; ++n) {
    auto angle = ::sweep_scan_get_angle(releasing_scan.get(), n);
    auto distance = ::sweep_scan_get_distance(releasing_scan.get(), n);
    auto signal = ::sweep_scan_get_signal_strength(releasing_scan.get(), n);

    result.samples.push_back(sample{angle, distance, signal});
  }

  return result;
}

void sweep::reset() { ::sweep_device_reset(device.get(), detail::error_to_exception{}); }

} // ns

#endif
like image 768
tyler124 Avatar asked Nov 29 '22 08:11

tyler124


1 Answers

A simplified version of your problem:

buggy.hpp

int function() { return 0; }

main.cpp

 #include "buggy.hpp"
 int main() { return 0; }

other.cpp

 #include "buggy.hpp"

The problem is that buggy.hpp is defining function, not just declaring. Once the header inclusion is expanded, that means function is declared in both main.cpp and other.cpp - and that is not allowed.

The fix is to declare function as inline which allows the function to be declared in multiple translation units.

inline int function() { return 0; }

In fact, allowing multiple definitions is the only meaning of inline to the C++ standard. Compilers may treat it as a hint that the function body may be expanded inline. Good ones won't; they are better at making that sort of decision that programmers).

like image 112
Martin Bonner supports Monica Avatar answered Dec 05 '22 18:12

Martin Bonner supports Monica