0

I intend to provide simple wrappers to the operating system API, which throw exceptions when errors happen. These wrappers are simple, and are all defined as inline functions in a header file. Since system API is supposed to be large, the header file is supposed to be huge as well, containing a large number of tiny inline functions. The problem is, if a shared library (.so) is compiled with the header file included, will all these tiny wrappers be compiled into the resulting binary, resulting in a large binary file, even when only a small part of the wrappers are actually used? What about the case with executables, will it be different? If it is the case, will splitting the wrappers into multiple header files be the only solution? Or should I make the wrappers internal linkage by specifying static?

Here is what I think. The wrappers may be ODR-used (e.g., taking its address). And on Linux platforms, functions with external linkage are exported by default (i.e., linkable by other binary modules). So I guess it may be necessary for the linker to actually generate outline definitions for them. Please refer to bullet point 3) in the Description section here.

A simple example wrapping CloseHandle() in Windows API:

inline void close_handle(HANDLE handle) {
  if (!CloseHandle(handle)) {
    throw std::system_error(GetLastError(), std::system_category(), "CloseHandle");
  }
}
Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • My feeling is that your question is too broad (you don't show any code), unclear, and you care too much about implicit details (you did not tell which) that the implementation does handle quite well in practice. Code a bit of your library first, then ask more focused questions with some actual source code in them. Be more specific: what OS, what compiler, what compilation flags, what source code? – Basile Starynkevitch Nov 16 '15 at 13:06
  • @BasileStarynkevitch You may be right. But what I want is an (almost) protable source-code-level solution. So, the OS, compiler, and compiler option details should not matter. I will add some simple example code. – Lingxi Nov 16 '15 at 13:14
  • The compiler options *does matter*, since some compilers (`g++` probably) won't inline functions if you don't ask them to optimize. – Basile Starynkevitch Nov 16 '15 at 13:21
  • @BasileStarynkevitch Actually, I do not care whether the functions are practically inlined or not. I do care whether binary is generated even when the functions are not used at all. And if it is, what could be an elegant and portable way to prevent it. – Lingxi Nov 16 '15 at 13:24
  • You should not care in practice. Trust your implementation, it is doing well enough. I don't understand why avoiding some (rare) inlined function to be outlined is so important. Most inlined functions *won't be outlined* (and the few that would be outlined would be outlined for some good reasons) – Basile Starynkevitch Nov 16 '15 at 13:24
  • I finally downvoted the question. You don't explain why you ask and what you really are afraid of. We cannot blindly guess. You should motivate your question much more. And you'll need to code millions of lines before code size considerations matter. – Basile Starynkevitch Nov 16 '15 at 13:36
  • Your library is not likely to be huge, e.g. like Qt is (did you try to compile Qt yourself?). You'll code less than a few hundred thousand lines (you'll need five years for that!) so your concerns are unrealistic – Basile Starynkevitch Nov 16 '15 at 13:45
  • @BasileStarynkevitch Yes. I'm just way too sensitive over certain things. Thanks for the discussion. – Lingxi Nov 16 '15 at 13:47

1 Answers1

2

A (rather small) function declared static inline (or often, just inline, or even a member function defined inside some class or struct) won't (in practice) appear in the code if it not used (see this), and will probably be inlined everywhere. Of course, you need to enable the optimizations in your compilation command. So, if using GCC, compile with g++ -Wall -O2 (and you might add -fverbose-asm -S and look inside the generated assembler code to check).

Some compilers (and probably g++) won't bother inlining if not asked to optimize. And inlining is always a optimization, which the compiler might not do in some occasions (in particular when storing the address of that function somewhere)

BTW, it may look you are reinventing a framework similar to POCO or to Qt. Did you consider using them instead?

Also, recent C++11 (and C++14) implementations are already wrapping a significant part of the OS API (in particular, standard C++ IO library and C++ thread support library and more recently C++14 TS), often already using exceptions, so better leverage on them and use a recent C++ compiler (for GCC, that means GCC 5.2 in November 2015).

(In other words, code your thing for C++11 at least, not C++98)

On Linux with GCC (or Clang/LLVM), if making a library, you might be interested in link-time-optimization (compile & link the library with g++ -O2 -flto), precompiled headers, visibility function attributes.

Regarding program libraries on Linux, read Program Library HowTo. For shared libraries, read Drepper's paper: How to Write Shared Libraries and this answer.

In practice, an inlined function in some library would often not be outlined in the library, but in the application program calling it. So if your shared library Foo defines in a public header <foo.h>

 inline int maxsq(int a, int b) {
    // you could add some conditional throw here...
    if (std::abs(a) < std::abs(b)) return b*b;
    else return a*a;
 }

then the object code of maxsq probably won't appear inside libfoo.so, but only in your program (which #include <foo.h> in its source code) if that program needs maxsq to be outlined, e.g. stores the address of maxsq somewhere (or if you did not ask for enough optimizations).

Remember that inlining is always an optimization, and some compiler may avoid it (even for good performance reasons) sometimes. In practice, trust your compiler (actually, your C++ implementation also includes the linker, which might "garbage collect" sections).

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 1
    [see here](http://stackoverflow.com/questions/10876930/should-one-never-use-static-inline-function) for some discussion of `static inline` in C++ – M.M Nov 16 '15 at 12:20
  • I hope to find a portable source-code-level solution that works without twiddling with compiler options. Besides, what I need is checked system API, not an entire framework. So, POCO or Qt does not meet my needs. They are both very nice, of course :) – Lingxi Nov 16 '15 at 12:35
  • You don't need twiddling compiler options. But IMHO, GCC is useless for *production code* without `-Wall` (to get most warnings) and without `-O2` to get optimizations, without which the performance of the binary program would be poor – Basile Starynkevitch Nov 16 '15 at 12:45
  • How about the case when the an inline function is ODR-used, e.g., when its address is taken? An outline definition should be mandatory in such cases, which is compiled into the binary. And the ODR-use may not be obvious. It may appear in another binary module. – Lingxi Nov 16 '15 at 12:51
  • The compiler is required to handle that case transparently. – Basile Starynkevitch Nov 16 '15 at 12:54
  • So, back to my question. If not specifying `static` and the visibility function attributes (which are compiler extensions), inline functions will indeed lead to binary inflation when compiling a shared library? – Lingxi Nov 16 '15 at 12:56
  • It depends and is implementation specific. In practice, you should trust the compiler (and ask it to optimize), which is doing quite well in general. Be more specific in your question (with some actual code). Also, most shared libraries have some code which a particular application won't use (but what is not used depend upon the app) – Basile Starynkevitch Nov 16 '15 at 12:57