I have a project, and the directory structure is:
.
├── bin
├── README.md
├── src
│ ├── blocking_deque
│ │ └── blocking_deque.hpp
│ ├── buffer
│ │ ├── buffer.cpp
│ │ └── buffer.h
│ ├── epoller
│ │ ├── epoller.cpp
│ │ └── epoller.h
│ └── log
│ ├── log.cpp
│ └── log.h
└── test
├── Makefile
└── test_log.cpp
log.h:
#ifndef LOG_H
#define LOG_H
#include <memory>
#include <string>
#include <thread>
#include <mutex>
#include "../blocking_deque/blocking_deque.hpp"
#include "../buffer/buffer.h"
class Log {
public:
// ...
bool is_open();
// ...
private:
Log();
virtual ~Log();
// ...
Buffer buf;
// ...
};
#endif // LOG_H
log.cpp:
#include <cstdio>
#include <ctime>
#include <cstring>
#include <cassert>
#include <cstdarg>
#include <sys/stat.h>
#include <sys/time.h>
#include "log.h"
Log::Log() {
// ...
}
Log::~Log() {
// ...
}
inline bool Log::is_open() {
// ...
}
buffer.h:
#ifndef BUFFER_H
#define BUFFER_H
#include <vector>
#include <string>
#include <atomic>
class Buffer {
// ...
};
#endif // BUFFER_H
buffer.cpp:
#include <sys/uio.h> // readv
#include <unistd.h> // write
#include <cerrno> // errno
#include <cassert> // assert
#include <algorithm> // copy
#include "buffer.h"
// ... definition of some members of Buffer
blocking_deque.hpp:
#ifndef BLOCKING_DEQUE_HPP
#define BLOCKING_DEQUE_HPP
#include <deque>
#include <condition_variable>
#include <mutex>
template <typename T>
class BlockingDeque {
// ...
};
// ... definition of some members
test_log.cpp:
#include "../src/log/log.h"
void test_log() {
using level_type = Log::level_type;
Log::get_instance()->init(1, "./test_log1", ".log", 0);
int cnt = 0;
for (level_type lv=3; lv>=0; --lv) {
Log::get_instance()->set_level(lv);
for (int i=0; i<10000; ++i) {
for (level_type new_lv=0; new_lv<=3; ++new_lv) {
LOG_BASE(new_lv, "%s ===== %d", "test", cnt++);
}
}
}
Log::get_instance()->init(1, "./test_log2", ".log", 5000);
cnt = 0;
for (level_type lv=0; lv<=3; ++lv) {
Log::get_instance()->set_level(lv);
for (int i=0; i<10000; ++i) {
for (level_type new_lv=3; new_lv>=0; --new_lv) {
LOG_BASE(new_lv, "%s ==== %d", "test", cnt++);
}
}
}
}
int main() {
test_log();
}
When I use g++ -g test/test_log.cpp src/blocking_deque/blocking_deque.hpp src/buffer/buffer.cpp src/log/log.cpp -o ./a, the compiler(specifically, it's the linker) informs me that undefined reference to some function. The detail is shown below:
/usr/bin/ld: /tmp/cc3lAVRd.o: in function `test_log()':
/home/fansuregrin/workshop/my_http_server/test/test_log.cpp:18: undefined reference to `Log::is_open()'
/usr/bin/ld: /home/fansuregrin/workshop/my_http_server/test/test_log.cpp:28: undefined reference to `Log::is_open()'
/usr/bin/ld: /tmp/ccnM4HDs.o: in function `Log::write(int, char const*, ...)':
/home/fansuregrin/workshop/my_http_server/src/log/log.cpp:167: undefined reference to `Buffer::has_written(unsigned long)'
collect2: error: ld returned 1 exit status
However, the Log::is_open() is defined in src/log/log.cpp, the Buffer::has_written(unsigned long) is defined in src/buffer/buffer.cpp. Why it can't be compiled?
==============================
The reason for the problem is inline!
After I removed the inlines affixed to Log::is_open and Buffer::has_written, then there is no error.