Jump to content

C++ Undefined symbols for architecture x86_64 on CMake

AlTech
Go to solution Solved by shadow_ray,
21 minutes ago, AluminiumTech said:

It's not?

 

The array size parameter is the problem here. The array doesn't like the size parameter being given as count. It requires both of the parameters it takes.

Sorry i gave a vague answer. std::array is a fixed size array. Its length must be known at compile time. What i meant is that std::vector should be used instead.

Hi,

 

so I've experienced some problems with compiling a library I made in C++. I'm relatively new to C++ so apologies in advance if there are mistakes.

 

The code at issue is a class I made wrapping around Vectors.

 

This is the header file

//
//
//

#ifndef DEVKIT_OBJECTLIST_HPP
#define DEVKIT_OBJECTLIST_HPP

#include <vector>

namespace AluminiumTech::DeveloperKit {

/**
 * A wrapper around the C++ Standard Library 'vector' class.
 */

    template<typename Object> class ObjectList {

    public:
        ~ObjectList();

        int count;

        int capacity();

        void clear();

        Object get(int32_t index);

        int indexOf(Object object);

        void add(Object object);

        void remove(Object object);
        void remove(int index);

        void replace(int index, Object newObject);
        void replace(Object oldObject, Object newObject);

        std::vector<Object> toVector();

        Object *toArray();

    protected:
        std::vector<Object> vec;
    };

}
#endif //DEVKIT_OBJECTLIST_HPP

 

and this is the source file

//
//
//

#include "ObjectList.hpp"

template<typename Object>
void AluminiumTech::DeveloperKit::ObjectList<Object>::clear() {
    vec.clear();
    count = 0;
}

template<typename Object>
Object AluminiumTech::DeveloperKit::ObjectList<Object>::get(int index) {
    if(count > 0){
        return vec.at(index);
    }
}

template<typename Object>
int AluminiumTech::DeveloperKit::ObjectList<Object>::indexOf(Object object) {
    int index = 0;

    for(auto a : vec){
        if(get(index) == object){
            return index;
        }

        index++;
    }
    return 0;
}

template<typename Object>
void AluminiumTech::DeveloperKit::ObjectList<Object>::add(Object object) {
    vec.assign(1, object);
    count++;
}

template<typename Object>
void AluminiumTech::DeveloperKit::ObjectList<Object>::remove(Object object) {
    if(count > 0){
        vec.remove(object);
       count--;
    }
}

template<typename Object>
void AluminiumTech::DeveloperKit::ObjectList<Object>::remove(int index) {
    if(count > 0){
        auto object = get(index);
        vec.remove(object);
        count--;
    }
}

template<typename Object>
std::vector <Object> AluminiumTech::DeveloperKit::ObjectList<Object>::toVector() {
    return vec;
}

template<typename Object>
int AluminiumTech::DeveloperKit::ObjectList<Object>::capacity() {
    return vec.capacity();
}

template<typename Object>
void AluminiumTech::DeveloperKit::ObjectList<Object>::replace(int index, Object newObject) {
    vec.at(index) = newObject;
}

template<typename Object>
void AluminiumTech::DeveloperKit::ObjectList<Object>::replace(Object oldObject, Object newObject) {
   int index = indexOf(oldObject);
   replace(index, newObject);
}

template<typename Object>
Object* AluminiumTech::DeveloperKit::ObjectList<Object>::toArray() {
    Object array[count];

    for(int index = 0; index < count; index++){
        array = get(index);
    }

    return array;
}

template<typename Object>
AluminiumTech::DeveloperKit::ObjectList<Object>::~ObjectList() {
    vec.clear();
}

 

 

These are the errors I get on macOS using Clang 12. I've tried compiling this on Windows using MSVC compiler also using CMake and it gives linking errors.

Quote

 "AluminiumTech::DeveloperKit::ObjectList<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::add(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)", referenced from:
      AluminiumTech::DeveloperKit::StringFormatter::split_toObjectList(char, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) in StringFormatter.cpp.o

Quote

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [libDeveloperKit.dylib] Error 1
make[2]: *** [CMakeFiles/DeveloperKit.dir/all] Error 2
make[1]: *** [CMakeFiles/DeveloperKit.dir/rule] Error 2
make: *** [DeveloperKit] Error 2

 

I'm really not sure what's going on and would appreciate any help.

Thanks :).

Judge a product on its own merits AND the company that made it.

How to setup MSI Afterburner OSD | How to make your AMD Radeon GPU more efficient with Radeon Chill | (Probably) Why LMG Merch shipping to the EU is expensive

Oneplus 6 (Early 2023 to present) | HP Envy 15" x360 R7 5700U (Mid 2021 to present) | Steam Deck (Late 2022 to present)

 

Mid 2023 AlTech Desktop Refresh - AMD R7 5800X (Mid 2023), XFX Radeon RX 6700XT MBA (Mid 2021), MSI X370 Gaming Pro Carbon (Early 2018), 32GB DDR4-3200 (16GB x2) (Mid 2022

Noctua NH-D15 (Early 2021), Corsair MP510 1.92TB NVMe SSD (Mid 2020), beQuiet Pure Wings 2 140mm x2 & 120mm x1 (Mid 2023),

Link to comment
Share on other sites

Link to post
Share on other sites

Can't really help with your compiler error, but it sounds like you've not referenced a library when compiling. How are you calling the compiler?

 

I noticed a slight bug in your indexOf method though. It returns "0" when the element is not found, which is a valid index. It should return -1 to indicate no element was found. Otherwise you can't distinguish between first element matching and no element matching.

Remember to either quote or @mention others, so they are notified of your reply

Link to comment
Share on other sites

Link to post
Share on other sites

16 minutes ago, Eigenvektor said:

Can't really help with your compiler error, but it sounds like you've not referenced a library when compiling. How are you calling the compiler?

CLion and CMake are automatically detecting what compiler to use based on the platform.

 

In the toolchain options I have arguments forcing C++17 to be used.

 

151731223_Screenshot2020-12-08at05_42_26.thumb.png.97842726b649fb193394e3b3bd30d7b4.png

 

Also, here's my CMakeLists file:

cmake_minimum_required(VERSION 3.17)
project(DeveloperKit)

set(CMAKE_CXX_STANDARD 17)

add_library(DeveloperKit SHARED

        Types/Lists/ObjectList/ObjectList.hpp
        Types/Lists/ObjectList/ObjectList.cpp

        Types/Lists/HashMap/HashMapV2.hpp
        Types/Lists/HashMap/HashMapV2.cpp

        Types/KeyValuePair.hpp

        Types/DeveloperTypes/Version/Version.hpp
        Types/DeveloperTypes/Version/Version.cpp

        StringManipulation/TextProcessors/StringFormatter/StringFormatter.hpp
        StringManipulation/TextProcessors/StringFormatter/StringFormatter.cpp

        StringManipulation/TextProcessors/GenericStringProcessing/GenericStringProcessor.hpp
        StringManipulation/TextProcessors/GenericStringProcessing/GenericStringProcessor.cpp

        StringManipulation/TextProcessors/SarcasmProcessing/SarcasmTextProcessor.hpp
        StringManipulation/TextProcessors/SarcasmProcessing/SarcasmTextProcessor.cpp

        enums&constants/StringConstants.hpp

        StringManipulation/deps/ResultsAveraging.cpp
        StringManipulation/deps/ResultsAveraging.hpp

        StringManipulation/TextProcessors/ClickBaitProcessing/ClickBaitTextProcessor.cpp
        StringManipulation/TextProcessors/ClickBaitProcessing/ClickBaitTextProcessor.hpp

        Types/DeveloperTypes/DateTime/Date/Date.cpp
        Types/DeveloperTypes/DateTime/Date/Date.hpp

        Types/DeveloperTypes/DateTime/Time/Time.cpp
        Types/DeveloperTypes/DateTime/Time/Time.hpp

        Types/DeveloperTypes/DateTime/DateTime.hpp

        Types/DeveloperTypes/Stopwatch/Stopwatch.hpp
        Types/DeveloperTypes/Stopwatch/Stopwatch.cpp)

 

16 minutes ago, Eigenvektor said:

I noticed a slight bug in your indexOf method though. It returns "0" when the element is not found, which is a valid index. It should return -1 to indicate no element was found. Otherwise you can't distinguish between first element matching and no element matching.

Thanks. I've fixed it.

 

I noticed another bug just now with the toArray method that I think I've fixed.

Judge a product on its own merits AND the company that made it.

How to setup MSI Afterburner OSD | How to make your AMD Radeon GPU more efficient with Radeon Chill | (Probably) Why LMG Merch shipping to the EU is expensive

Oneplus 6 (Early 2023 to present) | HP Envy 15" x360 R7 5700U (Mid 2021 to present) | Steam Deck (Late 2022 to present)

 

Mid 2023 AlTech Desktop Refresh - AMD R7 5800X (Mid 2023), XFX Radeon RX 6700XT MBA (Mid 2021), MSI X370 Gaming Pro Carbon (Early 2018), 32GB DDR4-3200 (16GB x2) (Mid 2022

Noctua NH-D15 (Early 2021), Corsair MP510 1.92TB NVMe SSD (Mid 2020), beQuiet Pure Wings 2 140mm x2 & 120mm x1 (Mid 2023),

Link to comment
Share on other sites

Link to post
Share on other sites

Indeed, as @gabrielcarvfer said, template definitions should be placed in the include file so they are completely visible in each compilation unit where they are included. The reason should be obvious, they can't be compiled, and linked later, the regular way since they need to be specialised for each diffirent template type they are invoked with.

Link to comment
Share on other sites

Link to post
Share on other sites

On 12/10/2020 at 4:02 AM, gabrielcarvfer said:

Could you try moving the template functions to the header file? They will then be loaded into each file (compilation unit) they're included, the template will get specialized and everything should work.

 

I think you could also specialize the template by calling it after each class definition for every header of the classes you're making based on it.

 

 

So I tried that and a few errors came up which I fixed but there's one last error that I can't seem to fix.

 

Since I had to redo the toArray method this has been happening.

 

Quote

error C2975: '_Size': invalid template argument for 'std::array', expected compile-time constant expression

 

count is this since the re-write:

static int_least32_t count;

 

std::array<Object, count> toArray(){
            std::array<Object, count> array;

            for(int_least32_t index = 0; index < count; index++){
                array[index] = get(index);
            }

            return array;
        }

 

Judge a product on its own merits AND the company that made it.

How to setup MSI Afterburner OSD | How to make your AMD Radeon GPU more efficient with Radeon Chill | (Probably) Why LMG Merch shipping to the EU is expensive

Oneplus 6 (Early 2023 to present) | HP Envy 15" x360 R7 5700U (Mid 2021 to present) | Steam Deck (Late 2022 to present)

 

Mid 2023 AlTech Desktop Refresh - AMD R7 5800X (Mid 2023), XFX Radeon RX 6700XT MBA (Mid 2021), MSI X370 Gaming Pro Carbon (Early 2018), 32GB DDR4-3200 (16GB x2) (Mid 2022

Noctua NH-D15 (Early 2021), Corsair MP510 1.92TB NVMe SSD (Mid 2020), beQuiet Pure Wings 2 140mm x2 & 120mm x1 (Mid 2023),

Link to comment
Share on other sites

Link to post
Share on other sites

 

45 minutes ago, AluminiumTech said:

error C2975: '_Size': invalid template argument for 'std::array', expected compile-time constant expression

I think it's helpful to think of templates as  class or function blueprints. The compiler will generate all the necessary functions with the specific types. You cannot create new versions in runtime.

 

Am I assuming right that it is not  the internal ObjectList::count?

 

ಠ_ಠ

Link to comment
Share on other sites

Link to post
Share on other sites

12 minutes ago, shadow_ray said:

 

I think it's helpful to think of templates as  class or function blueprints. The compiler will generate all the necessary functions with the specific types. You cannot create new versions in runtime.

 

Am I assuming right that it is not  the internal ObjectList::count?

 

No, it is the internal count object. I can’t pre-specify how big the array is because only the count object would know how big it is.

Judge a product on its own merits AND the company that made it.

How to setup MSI Afterburner OSD | How to make your AMD Radeon GPU more efficient with Radeon Chill | (Probably) Why LMG Merch shipping to the EU is expensive

Oneplus 6 (Early 2023 to present) | HP Envy 15" x360 R7 5700U (Mid 2021 to present) | Steam Deck (Late 2022 to present)

 

Mid 2023 AlTech Desktop Refresh - AMD R7 5800X (Mid 2023), XFX Radeon RX 6700XT MBA (Mid 2021), MSI X370 Gaming Pro Carbon (Early 2018), 32GB DDR4-3200 (16GB x2) (Mid 2022

Noctua NH-D15 (Early 2021), Corsair MP510 1.92TB NVMe SSD (Mid 2020), beQuiet Pure Wings 2 140mm x2 & 120mm x1 (Mid 2023),

Link to comment
Share on other sites

Link to post
Share on other sites

7 minutes ago, AluminiumTech said:

No, it is the internal count object.

Static variables in a class are shared by all the objects. For example it can be used to keep track of how many array objects where created but it makes no sense to store the array size in it bcz it's associated with the class and not with the object.

 

10 minutes ago, AluminiumTech said:

I can’t pre-specify how big the array is because only the count object would know how big it is.

Then it doesn't have to be a template parameter.

ಠ_ಠ

Link to comment
Share on other sites

Link to post
Share on other sites

6 minutes ago, shadow_ray said:

Static variables in a class are shared by all the objects. For example it can be used to keep track of how many array objects where created but it makes no sense to store the array size in it bcz it's associated with the class and not with the object.

 

Then it doesn't have to be a template parameter.

It's not?

 

The array size parameter is the problem here. The array doesn't like the size parameter being given as count.

Judge a product on its own merits AND the company that made it.

How to setup MSI Afterburner OSD | How to make your AMD Radeon GPU more efficient with Radeon Chill | (Probably) Why LMG Merch shipping to the EU is expensive

Oneplus 6 (Early 2023 to present) | HP Envy 15" x360 R7 5700U (Mid 2021 to present) | Steam Deck (Late 2022 to present)

 

Mid 2023 AlTech Desktop Refresh - AMD R7 5800X (Mid 2023), XFX Radeon RX 6700XT MBA (Mid 2021), MSI X370 Gaming Pro Carbon (Early 2018), 32GB DDR4-3200 (16GB x2) (Mid 2022

Noctua NH-D15 (Early 2021), Corsair MP510 1.92TB NVMe SSD (Mid 2020), beQuiet Pure Wings 2 140mm x2 & 120mm x1 (Mid 2023),

Link to comment
Share on other sites

Link to post
Share on other sites

21 minutes ago, AluminiumTech said:

It's not?

 

The array size parameter is the problem here. The array doesn't like the size parameter being given as count. It requires both of the parameters it takes.

Sorry i gave a vague answer. std::array is a fixed size array. Its length must be known at compile time. What i meant is that std::vector should be used instead.

ಠ_ಠ

Link to comment
Share on other sites

Link to post
Share on other sites

@AluminiumTech Template arguments must be constexpr since templates are "expanded" at compile time.

@gabrielcarvferNo! Don't use unsigned except for very special reasons such as bit manipulation. Always always use signed , I explained in detail in this post : https://linustechtips.com/topic/1082025-c-variable-storage-size-bytes/?do=findComment&comment=12727003

 

Link to comment
Share on other sites

Link to post
Share on other sites

25 minutes ago, gabrielcarvfer said:

I have no idea where did you got that from.
Unsigned is the proper type for monotonic counters (e.g. index offsets). The example you provided of a tachometer is not a monotonic counter.
You said it is easier to debug. If you're dealing with little tiny numbers and see a gigantic one, it should be obvious that there is an error.

I do agree that you should not use unsigned everywhere, but this is the exact place where it makes sense to use it other than bit manipulation and bigint soft-math.
Also, you should use iterators if you're not feeling confident in dealing with indexes/pointers. Way safer, has checks to prevent out-of-bounds, etc.

I'm not going to debate this much, this is an ongoing never ending debate between the two camps. But many years of experience has learned us that, those that think they can avoid the traps that come from mixing signed and unsigned, are the first to be bitten by them. And as said, in a real world program variables and their types propagate trough the program. You can't just use unsigned where it makes sense, because at some point the result will be used in another equation where it mixes with something signed.  You'll have to constantly keep track of the types involved and convert where necessary. It *will* bite you! Using signed everywhere (except very special occasions), and immediately safely converting any unsigned data to signed as soon as you get it, is the only way to go imho.

 

Even Stroustrup repeatedly admitted making size_t unsigned was a big mistake.

Watch this video from 42:40 https://channel9.msdn.com/Events/GoingNative/2013/Interactive-Panel-Ask-Us-Anything

Listen to the man, he knows his stuff.

Link to comment
Share on other sites

Link to post
Share on other sites

36 minutes ago, gabrielcarvfer said:

Monotonic counters used as address offsets/index are a very special case (e.g. primarily in C loops). Which is why using it makes sense.

Still not agreeing, sorry.

Signed allows for faster code, as signed overflow is undefined and opens up a whole suit of optimization options.

The difference between 2 offsets/indexes can be negative.

In C++ we have stuff like range based for loops and STL functions that can (should) replace many loops.

 

We've had to fix far too many bugs over the years because of this. Disagreeing with Stroustrup, Herb Sutter and Chandler Carruth reeks off exactly the over-confidence that'll get you caught in a really bad spot one day.

 

Again, the main issue here is that unsigned does not model numbers that cannot be negative, it models modular arithmetic. Like Carruth says in the video, when is the last time you wanted modular behavior? There are literally *no* upsides to using unsigned over signed, only downsides, why make life hard for yourself?

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×