Why the executable is not executable?

I have a hello world cpp file. If I compile it by c++ test.cpp -o test i get "test" file that is executable ( -rwxr-xr-x ) and if I execute it, it is executed and generates an expected result.

However, if I use ${CXX} -std=c++0x -I${INCLUDE_DIR1} -c test.cpp -o test -L{LIB_DIR1} -llib_name I also get the "test" file but in this case it is not executable. So, I cannot execute it. I tried to chmod +x , it gets permissions to be executed but if I try to execute it get an error message (cannot be executed).

What am I doing wrong and how it can be corrected?


-c tells the compiler to not generate an executable (it means "compile only"). It only creates an object file, that is suitable for being linked into an executable (possibly with other object files and libraries).

Remove the -c switch if you want an executable.

For more details on the complete compilation process, see: How does the compilation/linking process work?


It seems like you're at the very beginning of this whole programming madness. So, I do understand if you're having a hard time grasping what is a misnamed object (referred to as .o in this case) file, compiler parameters and what do they really do or even the library names.

My assumption is that, from the looks of it you're copying the line of shell script you are executing in order to produce your executable from an unknown example ( -llib_name makes it feel so, at least). So, I'll try to explain everything that is going on in here as simply, clearly and roughly as I can.

First of all, a C++ compiler compiles a given source file into relocatable machine code. If you store the emissions of a compiler (and compiler alone) in a file, this file would become the object file that is aforementioned (remember the .o file). If you paid attention, this entails that an object file contains relocatable machine code.

Now you have compiled your source code and you have its machine code equivalent stored in an object file. However, this object file is not directly executable; even though it does contain machine code which the CPU should have no problem executing. The problem is that, this machine code is not linked. So, here comes the second bullet-point: the relocatable machine code in an object file is not linked and hence cannot (well, more like should not) be executed. In addition to this, an object file may also contain additional metadata to help the linker with the linking process, which produces the actual executable. We will call the whole of this intermediate representation the object code.

So, now that we compiled our source code and emitted the object file, the next obvious and logical step would be to link the object file with whatever libraries and / or other object files you want in order to produce the executable that we can execute just like your first ./test binary. This is where the linker comes into play, the linker accepts object files and libraries (side note: roughly, libraries are collections of object files) and does some linking magic like resolving undefined references in object files across modules and arranging the address space of the executable, etc. The linker then emits a final executable conforming to the executable file format of the target platform for which the linker was invoked. It is this file that is emitted that you can execute like ./test .

So, now that you know the basics, let's see what's wrong with your shell invocations. First of all, you should learn that through invoking c++ you can both trigger the C++ compiler (I think it is either g++ or clang++ in this case) and the linker. Secondly, you should know that the -c flag tells the compiler to compile the given source file and emit its equivalent object code and machine code alone. So, invoking the C++ compiler without the -c flag not only causes it to compile the given source code but also to link the resulting object code and produce the final executable. This is what happens in your first command-line. The emitted file, named test is the linked executable file. However, in your second command-line the -c flag is present. In this case the compiler will be emitting nothing but the object code produced by compiling test.cpp . You'd be needing to link this resulting object file in order to produce the executable. Looks like you tell the compiler to store the object code that it produced in a file called test which is what Marc was telling about when he mentioned the misnaming (object files usually have the .o or .obj suffix).

From this point onwards you have two options, either to remove the -c flag or to link the object files. To compile and link (separately) the object files (including the probably-it-shouldn't-be-there™ liblib_name ):

${CXX} -std=c++0x -stdlib=libc++ -I${INCLUDE_DIR1} -c test.cpp -o test.o
${CXX} -std=c++0x -stdlib=libc++ -L${LIB_DIR1} -llib_name test.o -o test

I have taken the liberty of introducing libc++ there. If you're willing to use C++11 (you refer to it as C++0x) it's better if it's around. However, if you want to compile and link in one single line, the same thing can be achieved using this:

${CXX} -std=c++0x -stdlib=libc++ -I${INCLUDE_DIR1} -L${LIB_DIR1} -llib_name test.cpp -o test

These two do the exact same thing. But notice, how the one-liner version is lacking the -c flag.

Now that we have almost everything covered the last issue would be what do -I , -L and -l do. -I specifies a path which the compiler will be searching for header files included in your source code. This path doesn't override the default header search paths of the compiler, it just comes as an addition to them. -L is the same thing but for libraries. Your compiler will be looking for libraries you're explicitly linking against (such as liblib_name in this case) in this path. Again, this does not override the default library search paths. Finally the -l flag is used for specifying a library to the linker to link against while linking your executable. In your case you're linking against a library called liblib_name (the name specified for the -l flag omits the first lib in the library's filename) which you said your compiler complains about as non-existent. Are you sure you really want to link liblib_name into your executable? Is this even a real library? If not, then remove the entire -llib_name parameter and your compiler should stop yelling about it.

Sorry for the long, long, long explanations but I am hoping you learned a nibble here and a nibble there and all of this would be useful to you.

链接地址: http://www.djcxy.com/p/73318.html

上一篇: 对deque中的迭代器失效感到困惑

下一篇: 为什么可执行文件不可执行?