I am trying to build the simple gcc plugin. I am a newbie, but I want to implement more complicated plugins in the future.
I read a lot of manuals, and it seems that I did everything right, but something is wrong.
I can't build it. Every time I try to build my plugin I get an error:
/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/ccjmG33v.o: In function `plugin_init':
plugin.c:(.text+0x9e): undefined reference to `register_callback'
plugin.c:(.text+0xc6): undefined reference to `register_callback'
collect2: ld returned 1 exit status
make: *** [plugin.o] Error 1
I have no idea what is wrong. I performed the same steps as described in all the manuals I found.
I have Ubuntu 12.04 with gcc-4.6.3 compiler.
I installed gcc-4.6-plugin-dev.
I even tried to build the plugin, based on gcc_4.6.4, that was carefully downloaded and built by myself. But the result is the same.
My Makefile:
PLUGINS_DIR = /usr/lib/gcc/i686-linux-gnu/4.6/plugin/include
INCLUDES = \
-I$(PLUGINS_DIR)
DEFINES = -Dbool=int -DTRUE=1 -DFALSE=0
plugin.so : plugin.o
gcc -shared -Wl,-export-dynamic -o plugin.so plugin.o
%.o : %.c
gcc $(DEFINES) $(INCLUDES) -fPIC -o $# $^
clean :
rm *.o *.so
Plugin source code:
#include <aspell.h>
#include <gcc-plugin.h>
#include <coretypes.h>
#include <diagnostic.h>
#include <gimple.h>
#include <tree.h>
#include <tree-flow.h>
#include <tree-pass.h>
#define is_alpha(c) (((c)>64 && (c)<91) || ((c)>96 && (c)<123))
int plugin_is_GPL_compatible = 1;
static AspellSpeller *speller_g;
/* Help info about the plugin if one were to use gcc's --version --help */
static struct plugin_info speller_info =
{
.version = "42",
.help = "Hahahaha yeaaaaa....",
};
static struct plugin_gcc_version speller_ver =
{
.basever = "4.6",
};
/* We don't need to run any tests before we execute our plugin pass */
static bool speller_gate(void)
{
return true;
}
static const_tree is_str_cst(const_tree node)
{
/*
const_tree str = node;
// Filter out types we are ignoring
if (TREE_CODE(str) == VAR_DECL)
{
if (!(str = DECL_INITIAL(node)))
return NULL_TREE;
else if (TREE_OPERAND_LENGTH(str))
str = TREE_OPERAND(str, 0);
}
else if (TREE_CODE(str) == ADDR_EXPR &&
TREE_OPERAND_LENGTH(str) > 0)
str = TREE_OPERAND(str, 0);
if (TREE_CODE(str) != STRING_CST &&
TREE_OPERAND_LENGTH(str) > 0)
str = TREE_OPERAND(str, 0);
if (TREE_CODE(str) != STRING_CST)
return NULL_TREE;
else
return str;
*/
}
static AspellSpeller *init_spellchecker(void)
{
/*
AspellConfig *cfg;
AspellCanHaveError *err;
// Configure and instantiate a spell checker
cfg = new_aspell_config();
aspell_config_replace(cfg, "lang", "en_US");
err = new_aspell_speller(cfg);
if (aspell_error_number(err) != 0)
{
puts(aspell_error_message(err));
return NULL;
}
return to_aspell_speller(err);
*/
}
static void spell_check(const_gimple stmt, const_tree str)
{
/*
char buf[32] = {0};
const char *data, *end;
data = TREE_STRING_POINTER(str);
printf("Spell checking string: \'%s\'\n", data);
while (*data)
{
// Skip non alphas including whitespace
while (!is_alpha(data[0]))
{
if (data[0] == '\0')
return;
++data;
}
// Find the end of the word
end = data;
while (is_alpha(end[0]))
++end;
if ((end - data) > sizeof(buf))
return;
memcpy(buf, data, end - data);
buf[end-data] = '\0';
if (!(aspell_speller_check(speller_g, buf, end - data)))
warning_at(gimple_location(stmt), 0, "%s (bad spelling)", buf);
data = end;
}
*/
}
static unsigned speller_exec(void)
{
/*
unsigned i;
const_tree str, op;
basic_block bb;
gimple stmt;
gimple_stmt_iterator gsi;
FOR_EACH_BB(bb)
for (gsi=gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
{
stmt = gsi_stmt(gsi);
for (i=0; i<gimple_num_ops(stmt); ++i)
if ((op = gimple_op(stmt, i)) && (str = is_str_cst(op)))
spell_check(stmt, str);
}
return 0;
*/
}
/* See tree-pass.h for a list and desctiptions for the fields of this struct */
static struct gimple_opt_pass speller_pass =
{
.pass.type = GIMPLE_PASS,
.pass.name = "speller", /* For use in the dump file */
.pass.gate = speller_gate,
.pass.execute = speller_exec, /* Pass handler/callback */
};
/* Return 0 on success or error code on failure */
int plugin_init(struct plugin_name_args *info, /* Argument infor */
struct plugin_gcc_version *ver) /* Version of GCC */
{
struct register_pass_info pass;
if (strncmp(ver->basever, speller_ver.basever, strlen("4.6")))
return -1; /* Incorrect version of gcc */
pass.pass = &speller_pass.pass;
pass.reference_pass_name = "ssa";
pass.ref_pass_instance_number = 1;
pass.pos_op = PASS_POS_INSERT_AFTER;
/* Tell gcc we want to be called after the first SSA pass */
register_callback("speller", PLUGIN_PASS_MANAGER_SETUP, NULL, &pass);
register_callback("speller", PLUGIN_INFO, NULL, &speller_info);
/* Initilize our spell checker */
if (!(speller_g = init_spellchecker()))
return -1;
return 0;
}
The commented source code contains the function calls undefined for the linker too. As I understand, the problem is the same as for the register_callback function.
Could someone help me to cope with this trouble? The good, detailed, not out-of-date, manual about gcc plugins writing would be very useful too.
Any help would be greatly appreciated.
Try changing the second last line of the Makefile to:
%.o : %.c
gcc $(DEFINES) $(INCLUDES) -fPIC -o $# -c $^
Note the "-c" that I have added which tells it to compile, but not link during this phase.
This is exactly an example found online if not mistaken. When compiling the plugin, if gcc prompts that some of the libraries are not found, rather than using -I to specify each library one by one when compiling the plugin, can we use a Makefileto specify all these directories instead? Thanks
Related
I'm on MacOS Catalina 10.15.3. I'm trying to build Caonical's dqlite as I want to try the experimental features of k3s which uses it as distributed database instead of etcd or others.
The error I'm seeing is with one of the dependencies, libco.
I built the library with the following commands:
clang libco.c -g -O2 -Wall -fPIC -c -DLIBCO_MP
clang libco.o -dynamiclib -Wl,-install_name,libco.dylib -o libco.dylib
and I have moved these files to /usr/local/lib/libco.dylib and /usr/local/include/libco.h respectively.
The issue is raised when I try to build a simple test file (please ignore errors in this file, I tried adapting this one as stand-alone test):
#include <libco.h>
#include <stdlib.h>
#include <assert.h>
/* Execution context of a test coroutine, passed using the global ctx
* variable. */
struct ctx
{
cothread_t main; /* Reference to the main coroutine */
int v1;
int v2;
};
static struct ctx *ctx; /* Argument for test coroutines */
struct fixture
{
cothread_t main; /* Main coroutine */
cothread_t coro1; /* First coroutine */
cothread_t coro2; /* Second coroutine */
struct ctx ctx1; /* Context for first coroutine */
struct ctx ctx2; /* Context for second coroutine */
};
static void coro()
{
struct ctx *c = ctx;
c->v1 = 1;
co_switch(c->main);
c->v2 = 2;
co_switch(c->main);
}
int main()
{
struct fixture *f = malloc(sizeof *f);
f->main = co_active();
f->coro1 = co_create(1024 * 1024, coro);
f->coro2 = co_create(1024 * 1024, coro);
f->ctx1.main = f->main;
f->ctx2.main = f->main;
/* Start executing coro1 */
ctx = &f->ctx1;
co_switch(f->coro1);
/* The v1 field of the context has been initialized, but v2 has not. */
assert(f->ctx1.v1 == 1);
assert(f->ctx1.v2 == 0);
/* Start executing coro2 */
ctx = &f->ctx2;
co_switch(f->coro2);
/* The v1 field of the second context has been initialized, but v2 has
* not. */
assert(f->ctx2.v1 == 1);
assert(f->ctx2.v2 == 0);
/* The fields of the first context are still the same. */
assert(f->ctx1.v1 == 1);
assert(f->ctx1.v2 == 0);
/* Resume execution of coro2 */
co_switch(f->coro2);
/* The v2 field of the second context has been initialized too, but the
* one of the first context still hasn't. */
assert(f->ctx2.v1 == 1);
assert(f->ctx2.v2 == 2);
assert(f->ctx1.v1 == 1);
assert(f->ctx1.v2 == 0);
/* Resume execution of coro1 */
co_switch(f->coro1);
/* The v2 field of the first context has been initialized too now. */
assert(f->ctx1.v1 == 1);
assert(f->ctx1.v2 == 2);
co_delete(f->coro1);
co_delete(f->coro2);
free(f);
return 0;
}
Trying to compile using clang test.c -o test results in the following:
Undefined symbols for architecture x86_64:
"_co_active", referenced from:
_main in test-b98908.o
"_co_create", referenced from:
_main in test-b98908.o
"_co_delete", referenced from:
_main in test-b98908.o
"_co_switch", referenced from:
_main in test-b98908.o
_coro in test-b98908.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Upon further inspection, however, I find that those symbols seem to be defined in the libco.dylib library:
$ lipo -info /usr/local/lib/libco.dylib
Non-fat file: /usr/local/lib/libco.dylib is architecture: x86_64
$ nm /usr/local/lib/libco.dylib
U ___assert_rtn
0000000000005058 d __dyld_private
U __tlv_bootstrap
0000000000001d60 T _co_active
0000000000005040 s _co_active_buffer
0000000000005070 s _co_active_buffer$tlv$init
0000000000005028 s _co_active_handle
0000000000005060 s _co_active_handle$tlv$init
0000000000001e60 T _co_create
0000000000001f20 T _co_delete
0000000000001da0 T _co_derive
0000000000001f50 T _co_serializable
0000000000005270 b _co_swap
0000000000002000 s _co_swap_function
0000000000001f30 T _co_switch
0000000000001f60 t _crash
0000000000001f70 t _crash.cold.1
U _free
U _malloc
U _mprotect
U _sysconf
U dyld_stub_binder
I guess the only option remaining is that the compiler isn't finding the library, so the issue could be a name or library path resolution issue but I can't seem to figure it out.
What am I missing?
Thank you.
You need to tell clang where the include files are, which directory the libraries are in and which libraries you want to use:
clang program.c -o program -I/usr/local/include -L/usr/local/lib -lco
I have a strange segmentation fault that doesn't exist when everything is in 1 .c file, but does exist when I put part of the code in a dynamically linked library and link it to a test file. The complete code for the working 1 .c file code is at the bottom, the complete code for the error system with 2 .c and 1 .h file come first.
Here is the error system:
example.h:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p);
example.c:
#include "example.h"
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
example2.c:
This is essentially a test file:
#include "example.h"
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here2");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("Start");
test_print();
puts("Done");
return 0;
}
Makefile:
I link example to example2 here, and run:
example:
#clang -I . -dynamiclib \
-undefined dynamic_lookup \
-o example.dylib example.c
#clang example2.c example.dylib -o example2.o
#./example2.o
.PHONY: example
The output is:
$ make example
Start
Here1
Here 8
FOO
make: *** [example] Segmentation fault: 11
But it should show the full output of:
$ make example
Start
Here1
Here 8
FOO
BAR
Here2
Done
The weird thing is everything works if it is this system:
example.c:
#include <stdio.h>
#include <stdlib.h>
typedef struct MYARRAY {
int len;
void* items[];
} MYARRAY;
MYARRAY *collection;
void
mypush(void* p) {
printf("Here %lu\n", sizeof collection);
puts("FOO");
int len = collection->len++;
puts("BAR");
collection->items[len] = p;
}
void
test_print() {
puts("Here1");
mypush("foo");
puts("Here");
}
int
main() {
collection = malloc(sizeof *collection + (sizeof collection->items[0] * 1000));
collection->len = 0;
puts("ASF");
test_print();
return 0;
}
Makefile:
example:
#clang -o example example.c
#./example
.PHONY: example
Wondering why it's creating a segmentation fault when it is linked like this, and what I am doing wrong.
I have checked otool and with DYLD_PRINT_LIBRARIES=YES and it shows it is importing the dynamically linked libraries, but for some reason it's segmentation faulting when linked but works fine when it isn't linked.
Your problem is this, in example.h:
MYARRAY *collection;
Since both main.c and example.c include this file, you end up defining collection twice, which results in undefined behavior. You need to make sure you define each object only once. The details are relatively unimportant since anything can happen with undefined behavior, but what's probably happening is that main.c is allocating memory for one object, but the one example.c is using is still NULL. As mentioned in the comments, since you define collection in main.c your linker is able to build the executable without needing to look for that symbol in the dynamic library, so you don't get a link time warning about it being defined there too, and obviously there'd be no cause for a warning at the time you compile the library.
It works for you when you put everything in one file because obviously then you're not defining anything twice, anymore. The error itself is nothing to do with the fact you're using a dynamic library, although that may have made it harder to detect.
It would be better to define this in example.c and provide a constructor function, there's no need for main() to be able to access it directly. But if you must do this, then define it in example.c and just declare an extern identifier in the header file to tell main.c that the object is defined somewhere else.
I am trying to port some code to linux from Windows. I have gotten pretty far, but now I am stuck on an error with inheritance. But I can't figure out what's not working. It appears that It's not importing the header, but I can't figure out why because it seems to me that is should be working.
here is the error output:
/usr/bin/c++ -DHAVE_CLOGS -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_WIDGETS_LIB -std=c++11 -I/code/cuda/JF-Cut/src/build -I/code/cuda/JF-Cut/src/QVisualizer -I/code/cuda/clogs-install/include -I/usr/local/cuda-7.5/targets/x86_64-linux/include -isystem /opt/Qt/5.5/gcc_64/include -isystem /opt/Qt/5.5/gcc_64/include/QtWidgets -isystem /opt/Qt/5.5/gcc_64/include/QtGui -isystem /opt/Qt/5.5/gcc_64/include/QtCore -isystem /opt/Qt/5.5/gcc_64/./mkspecs/linux-g++ -fPIC -o CMakeFiles/QGCWidget.dir/Graph_Cut/QGCWidget.cpp.o -c /code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/QGCWidget.cpp
In file included from /code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/QGCWidget.cpp:44:0:
/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h:45:11: error: ‘cl::Error’ has not been declared
using cl::Error;
^
/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h:48:1: error: expected class-name before ‘{’ token
{
^
/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h: In member function ‘void QError::serialize(std::ostringstream&, cl_int)’:
/home/sansomk/code/cuda/JF-Cut/src/QVisualizer/Graph_Cut/../infrastructures/QError.h:68:13: error: ‘cl::Error’ has not been declared
cl::Error::serialize(s, code);
Here is the Code for QError.h
#ifndef QERROR_H
#define QERROR_H
#ifndef __CL_ENABLE_EXCEPTIONS
#define __CL_ENABLE_EXCEPTIONS
#endif
// removed #include "../3rdParty/cl/cl_stacktrace.hpp"
#if defined(__APPLE__) || defined(__MACOSX)
#include <OpenCL/cl.hpp>
#else
#include <CL/cl.hpp>
#endif
#define Q_LOGIC_ERROR -100
#define Q_INVALID_ARGUMENT -101
#define Q_LENGTH_ERROR -102
#define Q_OUT_OF_RANGE -103
#define Q_FUTURE_ERROR -104
#define Q_RUNTIME_ERROR -110
#define Q_RANGE_ERROR -111
#define Q_OVERFLOW_ERROR -112
#define Q_UNDERFLOW_ERROR -113
#define Q_SYSTEM_ERROR -114
using cl::Error;
class QError : public cl::Error
{
protected:
cl_int level_;
void serialize(std::ostringstream& s, cl_int code)
{
std::string error;
switch (code)
{
case Q_LOGIC_ERROR: error = "Q_LOGIC_ERROR"; break;
case Q_INVALID_ARGUMENT: error = "Q_INVALID_ARGUMENT"; break;
case Q_LENGTH_ERROR: error = "Q_LENGTH_ERROR"; break;
case Q_OUT_OF_RANGE: error = "Q_OUT_OF_RANGE"; break;
case Q_FUTURE_ERROR: error = "Q_FUTURE_ERROR"; break;
case Q_RUNTIME_ERROR: error = "Q_RUNTIME_ERROR"; break;
case Q_RANGE_ERROR: error = "Q_RANGE_ERROR"; break;
case Q_OVERFLOW_ERROR: error = "Q_OVERFLOW_ERROR"; break;
case Q_UNDERFLOW_ERROR: error = "Q_UNDERFLOW_ERROR"; break;
case Q_SYSTEM_ERROR: error = "Q_SYSTEM_ERROR"; break;
}
if (!error.empty()) s << " > " << error << ", ";
cl::Error::serialize(s, code);
}
public:
QError(cl_int level, cl_int err, const char * errStr = NULL) : level_(level), cl::Error(err, errStr) {}
~QError() throw() {}
cl_int level(void) const { return level_; }
virtual const char * what() throw ()
{
std::ostringstream s;
serialize(s, err_);
errStr_ = s.str();
return errStr_.c_str();
}
};
#endif // QERROR_H
In order to use cl::Error you need to define __CL_ENABLE_EXCEPTIONS.
I can see you have it there, but that file is a header file. If you include OpenCL headers somewhere else earlier in the compilation unit (.cpp) without defining __CL_ENABLE_EXCEPTIONS. Then the later includes will simply skip (due to ifdefs in the header file to avoid multiple instances of the same .h file).
What you should do for these types of global compilation defines, is declare them in the command line.
g++ ... -D__CL_ENABLE_EXCEPTIONS
That way you ensure the defines are enabled at the very beginning of the compilation.
I am trying to compile a library from https://github.com/simongog/sdsl-lite and I am not able to compile.
I am using g++ 4.8.3 and the message that I got from compilation is that stoull was not declared in this scope:
This is the code that is throwing the error:
uint64_t _parse_number(std::string::const_iterator& c, const std::string::const_iterator& end)
{
std::string::const_iterator s = c;
while (c != end and isdigit(*c)) ++c;
if (c > s) {
return stoull(std::string(s,c));
} else {
return 0;
}
}
I have tried with different flags: c++0x, c++11 and gnu++11 but without success.
Do you have any clue how to fix this?
Thanks in advance.
I'm having a really hard time getting an R library installed that requires some compilation in C. I'm using a Mac OSX Snow Leopard machine and trying to install this R package (here).
I've looked at the thread talking about getline on macs and have tried a few of these fixes, but nothing is working! I'm a newbie and don't know any C, so that may be why! Can anyone give me some tips on how I could modify files in this package to get it to install?? Anyhelp would be pathetically appreciated! Here's the error I'm getting:
** libs
** arch - i386
g++ -arch i386 -I/Library/Frameworks/R.framework/Resources/include -I/Library/Frameworks/R.framework/Resources/include/i386 -I/usr/local/include -D_FASTMAP -DMAQ_LONGREADS -fPIC -g -O2 -c bed2vector.C -o bed2vector.o
In file included from /usr/include/c++/4.2.1/backward/strstream:51,
from bed2vector.C:8:
/usr/include/c++/4.2.1/backward/backward_warning.h:32:2: warning: #warning This file includes at least one deprecated or antiquated header. Please consider using one of the 32 headers found in section 17.4.1.2 of the C++ standard. Examples include substituting the <X> header for the <X.h> header for C++ includes, or <iostream> instead of the deprecated header <iostream.h>. To disable this warning use -Wno-deprecated.
bed2vector.C: In function ‘int get_a_line(FILE*, BZFILE*, int, std::string&)’:
bed2vector.C:74: error: no matching function for call to ‘getline(char**, size_t*, FILE*&)’
make: *** [bed2vector.o] Error 1
chmod: /Library/Frameworks/R.framework/Resources/library/spp/libs/i386/*: No such file or directory
ERROR: compilation failed for package 'spp'
The easiest solution is probably to add a static definition for getline() to bed2vector.c. This might be good enough:
/* PASTE AT TOP OF FILE */
#include <stdio.h> /* flockfile, getc_unlocked, funlockfile */
#include <stdlib.h> /* malloc, realloc */
#include <errno.h> /* errno */
#include <unistd.h> /* ssize_t */
extern "C" ssize_t getline(char **lineptr, size_t *n, FILE *stream);
/* PASTE REMAINDER AT BOTTOM OF FILE */
ssize_t
getline(char **linep, size_t *np, FILE *stream)
{
char *p = NULL;
size_t i = 0;
if (!linep || !np) {
errno = EINVAL;
return -1;
}
if (!(*linep) || !(*np)) {
*np = 120;
*linep = (char *)malloc(*np);
if (!(*linep)) {
return -1;
}
}
flockfile(stream);
p = *linep;
for (int ch = 0; (ch = getc_unlocked(stream)) != EOF;) {
if (i > *np) {
/* Grow *linep. */
size_t m = *np * 2;
char *s = (char *)realloc(*linep, m);
if (!s) {
int error = errno;
funlockfile(stream);
errno = error;
return -1;
}
*linep = s;
*np = m;
}
p[i] = ch;
if ('\n' == ch) break;
i += 1;
}
funlockfile(stream);
/* Null-terminate the string. */
if (i > *np) {
/* Grow *linep. */
size_t m = *np * 2;
char *s = (char *)realloc(*linep, m);
if (!s) {
return -1;
}
*linep = s;
*np = m;
}
p[i + 1] = '\0';
return ((i > 0)? i : -1);
}
This doesn't handle the case where the line is longer than the maximum value that ssize_t can represent. If you run into that case, you've likely got other problems.
Zeroth question: Have you considered using a package manager like fink or MacPorts rather than compiling yourself? I know that fink has an R package.
First question: How is the R build managed? Is there a ./configure? If so have you looked at the options to it? Does it use make? Scons? Some other dependency manager?
Second question: Have you told the build system that you are working on a Mac? Can you specify that you don't have a libc with native getline?
If the build system doesn't support Mac OS---but I image that R's does---you are probably going to have to download the standalone version, and hack the build to include it. How exactly you do that depends on the build system. And you may need to hack the source some.