Clang Error linker command failed with exit code 1

Hi and Merry Christmas to you all
This is my veri first C++ program that I wrote, and I get an error while trying to compiling (according to lecturer we have to run make clean all).
And I get the following errors:


and my code are divided in 2 files (assembler.cpp and main.cpp). The question is why do I get this errors. I don't understand and did many search without making any progress.

The assembler.cpp code is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include "assembler.hpp"

// ------------------------------------- //

/* ---------------------- *\
			Add your code here
		\* ---------------------- */

// ------------------------------------- //
const int REGISTERS_SIZE = 8;

int GetRegIndex(std::string reg)
{
	char nr = reg[1];
	int number = nr;
	number -= 48;
	return number;
}

int GetConstant(std::string constant)
{
	std::string constantNumber;
	for (int i = 0; i < sizeof(constant); i++)
	{
		if (i == 0)
		{
			continue;
		}
		else
		{
			constantNumber += constant[i];
		}
	}
	return std::stoi(constantNumber);
}

bool isReg(std::string term)
{
	if (term[0] == 'R')
	{
		return true;
	}
	return false;
}

int ExtractValue(std::string source, int *registers)
{
	if (isReg(source))
	{
		int GetRegIndexResult = registers[GetRegIndex(source)];
		return GetRegIndexResult;
	}
	return GetConstant(source);
}

bool BuildCommandList(std::vector<std::vector<std::string>> &commandList, std::string filepath)
{
	std::vector<std::string> lableName;
	std::vector<std::string> lableRows;
	std::string line;
	std::fstream file;
	file.open(filepath);
	if (!file)
	{
		return false;
	}
	while (std::getline(file, line))
	{
		// Check if line is not empty
		if (line.length() != 0)
		{

			// Check if line is lable
			int lengthLableLine = line.length();
			if (line[lengthLableLine - 1] == ':')
			{
				// Remove : from the line and push it to lableName
				line = line.substr(0, line.size() - 1);
				lableName.push_back(line);
				// Put commandListLength into lableRows
				std::string commandListLength = std::to_string(commandList.size());
				lableRows.push_back(commandListLength);
			}
			else
			{
				std::vector<std::string> lineParts;
				std::string word;
				for (int i = 0; i < line.length(); i++)
				{
					if (line[i] != ' ')
					{
						word += line[i];
					}
					else
					{
						lineParts.push_back(word);
					}
				}
				commandList.push_back(lineParts);
			}
		}
	}
	file.close();

	for (int i = 0; i < commandList.size(); i++)
	{
		if (commandList[i][0] == "JEQ" || commandList[i][0] == "JGT" || commandList[i][0] == "JLT")
		{
			int index = -1;
			for (int j = 0; j < lableName.size(); j++)
			{
				if (lableName[j] == commandList[i][1])
				{
					index = j;
				}
			}
			commandList[i][1] = lableRows[index];
		}
	}
	return true;
}

int PeekNextcommand(int *registers)
{
	int registers_length = sizeof(registers) - 2;
	return registers[registers_length];
}

int GetAndStepCommandIndex(int *registers)
{
	int index = registers[REGISTERS_SIZE - 1];
	registers[REGISTERS_SIZE - 1] += 1;
	return index;
}

void MOV(std::vector<std::string> &command, int *registers)
{
	int destIndex = GetRegIndex(command[1]);
	int value = ExtractValue(command[2], registers);
	registers[destIndex] = value;
}

void ADD(std::vector<std::string> &command, int *registers)
{
	int destIndex = GetRegIndex(command[1]);
	int term1 = ExtractValue(command[2], registers);
	int term2 = ExtractValue(command[3], registers);
	registers[destIndex] = term1 + term2;
}

void SUB(std::vector<std::string> &command, int *registers)
{
	int destIndex = GetRegIndex(command[1]);
	int term1 = ExtractValue(command[2], registers);
	int term2 = ExtractValue(command[3], registers);
	registers[destIndex] = term1 - term2;
}

void CMP(std::vector<std::string> &command, int *registers)
{
	int value1 = ExtractValue(command[1], registers);
	int value2 = ExtractValue(command[2], registers);

	if (value1 == value2)
	{
		registers[REGISTERS_SIZE - 2] = 1;
	}
	else if (value1 > value2)
	{
		registers[REGISTERS_SIZE - 2] = 2;
	}
	else
	{
		registers[REGISTERS_SIZE - 2] = 3;
	}
}

void JEQ(std::vector<std::string> &command, int *registers)
{
	if (registers[REGISTERS_SIZE - 2] == 1)
	{
		registers[REGISTERS_SIZE - 1] = std::stoi(command[1]);
	}
}

void JGT(std::vector<std::string> &command, int *registers)
{
	if (registers[REGISTERS_SIZE - 2] == 2)
	{
		registers[REGISTERS_SIZE - 1] = std::stoi(command[1]);
	}
}

void JLT(std::vector<std::string> &command, int *registers)
{
	if (registers[REGISTERS_SIZE - 2] == 3)
	{
		registers[REGISTERS_SIZE - 1] = std::stoi(command[1]);
	}
}




And the main.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <string>
#include <vector>
#include "assembler.hpp"



int main(int argc, char **argv)
{
	// Validate input arguments
	if (argc <= 1 || argc > (ASM::REGISTER_SIZE + 1))
	{
		std::cout << "Error: Invalid argument list.\n"
				  << "\n\nFormat: python3 interpreter.py program.asm (R0) (R1) (R3) (R4) ... (R7)\n"
				  << "\n\nArgument list explanationd:\n"
				  << "\n(REQUIRED) program.asm : The executable assembly file\n"
				  << "\n(OPTIONAL) (R0) : Default value for the register R0\n"
				  << "\n(OPTIONAL) (R1) : Default value for the register R1\n"
				  << "\n(OPTIONAL) (R2) : Default value for the register R2\n"
				  << "\n(OPTIONAL) (R3) : Default value for the register R3\n"
				  << "\n(OPTIONAL) (...) : Default value for the register ...\n"
				  << "\n(OPTIONAL) (R7) : Default value for the register R7\n";
		return 0;
	}

	// Create register state and load default arguments
	int registers[ASM::REGISTER_SIZE] = {0};

	for (int i = 2; i < argc; i++)
		registers[i - 2] = std::stoi(argv[i]);

	// Create the command list
	std::vector<std::vector<std::string>> commandList;

	/*
		A command in command list can be accessed by
		std::vector<std::string>& command = commandList[index];

		and each element in the command can be accessed by
		command[0]; // "MOV" for example
	*/

	if (ASM::BuildCommandList(commandList, argv[1]) == false)
	{
		std::cout << "Error: Could not open file '" << argv[1] << "'" << std::endl;
		return 0;
	}

	// ------------------------------------- //

	/* ---------------------- *\
				Add your code here
			\* ---------------------- */

	while (ASM::PeekNextCommandIndex(registers) < commandList.size())
	{
		std::vector<std::string> command = commandList[ASM::GetAndStepCommandIndex(registers)];
		if (command[0] == "MOV")
		{
			ASM::MOV(command, registers);
		}
		else if (command[0] == "ADD")
		{
			ASM::ADD(command, registers);
		}
		else if (command[0] == "SUB")
		{
			ASM::SUB(command, registers);
		}
		else if (command[0] == "CMP")
		{
			ASM::CMP(command, registers);
		}
		else if (command[0] == "JEQ")
		{
			ASM::JEQ(command, registers);
		}
		else if (command[0] == "JGT")
		{
			ASM::JGT(command, registers);
		}
		else if (command[0] == "JLT")
		{
			ASM::JLT(command, registers);
		}
	}

	// ------------------------------------- //

	// End application by printing the first four registers
	for (int i = 0; i < 4; i++)
		std::cout << registers[i] << " ";
	std::cout << std::endl;

	return 0;
}


Last edited on
I post the error logs and the header file source here due to limitation of maximum character for each post:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef ASSEMBLER_HPP
#define ASSEMBLER_HPP

#include <vector>
#include <string>

namespace ASM
{
	/*
		Everying in this namespace can be accessed by ASM::name
		
		For example:
		ASM::REGISTER_SIZE
		ASM::PeekNextCommandIndex(<arguments>)
		ASM::ADD(<arguments>)
	*/

	// Number of registers this implementation support
	constexpr int REGISTER_SIZE = 8;

	// ################################## //
	// ###### EXPOSED ASSEMBLER API ##### //
	// ################################## //

	// General command construction and reading

	bool BuildCommandList(std::vector<std::vector<std::string>>& commandList, std::string filepath);
	int PeekNextCommandIndex(int* registers);
	int GetAndStepCommandIndex(int* registers);

	// Assignment intructions

	void MOV(std::vector<std::string>& command, int* registers);
	
	// Arithmetic instructions

	void ADD(std::vector<std::string>& command, int* registers);
	void SUB(std::vector<std::string>& command, int* registers);
	
	// Conditional instructions

	void CMP(std::vector<std::string>& command, int* registers);
	void JEQ(std::vector<std::string>& command, int* registers);
	void JGT(std::vector<std::string>& command, int* registers);
	void JLT(std::vector<std::string>& command, int* registers);
}

#endif 



and finnaly the error is as follow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
habib@DESKTOP-NOT6K1R:/mnt/c/Users/hheza/OneDrive/Developments/c-plus-plus/uppgift1/cpp$ make clean all
rm -f app
rm -f runtests
rm -f assignment1-DV1626-assembler.zip
find . -name "*.gcda" -print0 | xargs -0 rm -f
find . -name "*.gcno" -print0 | xargs -0 rm -f
find . -name "*.o" -print0 | xargs -0 rm -f
clang -x c++ -c -Wall -std=c++17  -Iinclude  -Itest/include main.cpp -o main.o
clang -x c++ -c -Wall -std=c++17  -Iinclude  -Itest/include src/assembler.cpp -o src/assembler.o
clang -lstdc++ -lm main.o src/assembler.o -o app
/usr/bin/ld: main.o: in function `main':
main.cpp:(.text+0x235): undefined reference to `ASM::BuildCommandList(std::vector<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, std::allocator<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
/usr/bin/ld: main.cpp:(.text+0x346): undefined reference to `ASM::PeekNextCommandIndex(int*)'
/usr/bin/ld: main.cpp:(.text+0x386): undefined reference to `ASM::GetAndStepCommandIndex(int*)'
/usr/bin/ld: main.cpp:(.text+0x405): undefined reference to `ASM::MOV(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
/usr/bin/ld: main.cpp:(.text+0x472): undefined reference to `ASM::ADD(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
/usr/bin/ld: main.cpp:(.text+0x4c7): undefined reference to `ASM::SUB(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
/usr/bin/ld: main.cpp:(.text+0x51c): undefined reference to `ASM::CMP(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
/usr/bin/ld: main.cpp:(.text+0x571): undefined reference to `ASM::JEQ(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
/usr/bin/ld: main.cpp:(.text+0x5c6): undefined reference to `ASM::JGT(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
/usr/bin/ld: main.cpp:(.text+0x61b): undefined reference to `ASM::JLT(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&, int*)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [makefile:34: app] Error 1 



Thank you in advance for your time and response. I appreciate all helps <3
Last edited on
Shouldn't the functions defined in the assembler.hpp files have the functions declared within the ASM namespace in assembler.cpp file?

Hi,

In the assembler.cpp file you need to put ASM:: before each function definition, as in:

1
2
3
4
5
int ASM::PeekNextcommand(int *registers)
{
	int registers_length = sizeof(registers) - 2;
	return registers[registers_length];
}


Good Luck !!
Thank u all <3 for responses.
My problem is solved now.
Hello habiballahafg,

Another option would be to put this around everything in the "assembler.cpp" file.

1
2
3
4
namespace ASM
{

}


Something I did a while back that worked out.

Andy
Thanks Handy for your great solution <3
Topic archived. No new replies allowed.