Create dynamic library using MSVC command line - c

I've read a lot of posts and yet I don't understand how to create a simple dynamic library on windows using MSVC in command line. What I'm doing is:
1º) Code the DLL
dynamic.h
#pragma once
__declspec(dllexport) void HelloWorld();
dynamic.c
#include "dynamic.h"
#include <stdio.h>
void HelloWorld(){
printf("Hello World");
}
2º) Compile it
cl /LD dynamic.c
(it compiles correctly and without errors generating dynamic.dll and dynamic.lib)
3º) Try to test it
main.c
#include<stdio.h>
#include"dynamic.h"
int main(){
HelloWorld();
return 0;
}
cl main.c dynamic.lib
ERROR (by cl.exe x64)
main.cpp
Microsoft (R) Incremental Linker Version 14.16.27034.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
.\dynamic.lib
main.obj : error LNK2019: unresolved external symbol "void __cdecl HelloWorld(void)" (?HelloWorld##YAXXZ) referred in main
main.exe : fatal error LNK1120: unresolved externals
Please teach me how dynamic libraries compilation really work because I can't understand

In main.c it needs to see the function declaration like this:
__declspec(dllimport) void HelloWorld();
So you cannot use the same dynamic.h as you currently have, for both building the DLL and building main.c .
Normally people will use a preprocessor setup so the same header file has a different declspec depending who is including it, for example:
// dynamic.h
#ifndef DLL_FUNCTION
#define DLL_FUNCTION __declspec(dllimport)
#endif
DLL_FUNCTION void HelloWorld();
dynamic.c (in the DLL):
#define DLL_FUNCTION __declspec(dllexport)
#include "dynamic.h"

Try this way in dynamic.h :
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) void HelloWorld();
#ifdef __cplusplus
}
#endif
Use 'dumpbin.exe /exports dynamic.dll' to show exported symbols

Related

Mixing C++ and C code - Linker issues in VS10

I've got a problem mixing the C++ and C code. My C++ code was created in VS10, i.e is a Windows Form project. I want include my C function in my C++ function through of linker (.obj). The steps are:
Windows Form project
VS10 default project
Call the C function
Build the project manually using msbuild
C code
Build the project manually through a make file using nmake and generates the objects files (.obj)
With the every objects files in hands (Cpp and C), the objects are linked in a third makefile. It's a simple idea but it doesn't work. The build in msbuild show the following message:
error LNK2028: unresolved token (0A00000C) "extern "C" void __clrcall MinhaFuncao(void)" (?MinhaFuncao##$$J0YMXXZ) referenced in function "int __clrcall main(cli::array^)" (?main##$$HYMHP$01AP$AAVString#System###Z)
error LNK2019: unresolved external symbol "extern "C" void __clrcall MinhaFuncao(void)" (?MinhaFuncao##$$J0YMXXZ) referenced in function "int __clrcall main(cli::array^)" (?main##$$HYMHP$01AP$AAVString#System###Z)
The Cpp code:
#include "stdafx.h"
#include "Form1.h"
//#include"complex.h"
extern "C" {
#include "complex.h"
}
/*extern "C" {
void MinhaFuncao();
}*/
extern "C" void MinhaFuncao();
using namespace WFormTesting;
[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
MinhaFuncao(); //<--- Calling the Function HERE -->
// Create the main window and run it
Application::Run(gcnew Form1());
return 0;
}
The C code:
#include "complex.h"
void MinhaFuncao()
{
printf("My function AOWWW.\n");
}
The header file:
#ifndef COMPLEX_H_
#define COMPLEX_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdio.h>
void MinhaFuncao();
#ifdef __cplusplus
} // extern "C"
#endif
#endif
Has someone got an idea about this problem? I read others posts about linker issues, but the solutions proposed don't work for me. I believe that the difference is due to the msbuild and the VS project... :/
You are using extern "C" in an extern C block
remove the outer extern C block surrounding
#include "complex.h"

extern keyword behavior with Visual Studio

I had created this minimal example to illustrate my problem with extern declaration with Visual Studio 2008 (required to compile a python 2.7 extension). The same example is working well with gcc.
The result is that I have 2 separate global_var variables instead of a unique one in lib.c
the library interface : lib.h
#ifndef LIB_H
#define LIB_H 1
int __declspec( dllexport ) displayGlob();
#endif // LIB_H
the library code
// lib.c
#include<stdio.h>
int global_var=2;
int __declspec( dllexport ) displayGlob() {
printf("lib.c global_var=%d\n", global_var);
return global_var;
}
the user code that uses the library variable "global_var" and function displayGlob()
// main.c
#include"lib.h"
#include<stdio.h>
#include<stdlib.h>
extern int global_var=0; // must be initialized otherwise "error LNK2001: unresolved external symbol global_var"
int main(int argc, char *argv[])
{
printf("main.c global_var=%d\n", global_var);
displayGlob();
global_var = 3;
printf("main.c global_var=%d\n", global_var);
displayGlob();
exit(0);
}
execution result is:
main.c global_var=0
lib.c global_var=2
main.c global_var=3
lib.c global_var=2
Questions:
1 - Why must I initialize the extern variable in lib.h with Visual Studio and not Gcc ?
2 - Why the global_var lib.c displayed by the second displayGlob() is not modified to 3 ?
thanks for any hint !
Laurent
UPDATE: moved extern declaration of global_var from lib.h to main.c (even simpler example)
and of course problems remain...
Because C preprocesor basically pastes the content when you call #include, it the same as you declared your extern inside of main.c file. This means that this symbol is defined twice (in main.c and in lib.c).
What you should do is to add extern declaration to lib.c (for example by including lib.h) and initialize the value there, then remove initialization from lib.h.
So it should be like this:
lib.h:
extern global_var;
lib.c:
#include "lib.h"
int global_var=2;
main.c
#include "lib.h"
(no global_var definition/declaration here)
Solved myself, my fault.
Under Gcc I built both a static library and a dynamic library. My main.c was linked with the STATIC library, so variable resolution between lib.c and main.c was resolved at link time. I forgot that.
Under Visual Studio, I only built a DYNAMIC library, so it was normal variable linkage could not happen between the DLL and main.o
Sorry for any confusion created...

C / CUDA implementation with external variables produces linker error (unresolved external symbol)

I have a C-Project, which I would like to boost using a CUDA-module. But somehow, the externally defined variables can not be resolved. I am using Microsoft Visual C++ 2010 Express and CUDA Toolkit 5.0.
The following shows my minimal (not) working example:
main.c:
#include "main.h"
#include <stdio.h>
#include "cuda_test.cu"
int main( int argc, const char* argv[] )
{
testfunc();
return 1;
}
main.h:
#ifndef main_h
#define main_h
extern float PI;
#endif
testfile.c:
#include "main.h"
float PI = 3;
cuda_test.cu:
#include "main.h"
#include <stdio.h>
void testfunc()
{
printf("Hello from cudafile: %E", PI);
}
This yields the following error:
1>------ Build started: Project: cuda_min, Configuration: Debug Win32 ------
1>cuda_test.cu.obj : error LNK2001: unresolved external symbol "float PI" (?PI##3MA)
1>D:\Backup\diplomarbeit\cuda_xanthos\cuda_min\Debug\cuda_min.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
When passing the variable PI to the function testfunc, I get the desired behavior. This is what I am doing in my project (which actually uses the CUDA-device), but I really do not want to pass about 20 variables to my functions.
I suppose I am missing some setting for nvcc...
Any help would be much appreciated.
.cu is compiled and linked as .cpp, not .c. So, you can either rename your .c files to .cpp, or use extern "C" in your .cu file.

Apple Mach-O Link Error with curses.h

I've been getting this error numerous times in my program. I've simplified things down a bit to illustrate the basics and am still getting errors. I was told that I needed to add this library file to my project for it to work (libncurses.dylib) and it did solve some problems, but not this one.
Here is my code:
// screen.h
#ifndef screen_h
#define screen_h
#define MAC 1
#define WIN 2
#define LNX 3
#ifdef PLATFORM
#undef PLATFORM
#endif
#define PLATFORM MAC
void screen_erase();
#endif
// screen.c
#include <string.h>
#include <stdlib.h>
#include "screen.h"
#if PLATFORM == MAC
#include <curses.h>
void screen_erase(){
erase();
}
#endif
// main.cpp
#include <iostream>
#include <curses.h>
#include "screen.h"
using namespace std;
int main(){
screen_erase();
}
And here's the error I am getting:
Undefined symbols for architecture x86_64:
"screen_erase()", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation
What's going on here?
It's because you mix two different languages: C and C++.
In the screen.h header file, change the declaration to this:
#ifdef __cplusplus
extern "C" {
#endif
void screen_erase();
#ifdef __cplusplus
}
#endif
That tells the C++ compiler to not do name mangling on the screen_erase function name.

Create a valid shared library in C

I'm doing some test to learn how to create shared library.
The template for shared libraries in Code::Blocks is this
library.c
// The functions contained in this file are pretty dummy
// and are included only as a placeholder. Nevertheless,
// they *will* get included in the shared library if you
// don't remove them :)
//
// Obviously, you 'll have to write yourself the super-duper
// functions to include in the resulting library...
// Also, it's not necessary to write every function in this file.
// Feel free to add more files in this project. They will be
// included in the resulting library.
// A function adding two integers and returning the result
int SampleAddInt(int i1, int i2)
{
return i1 + i2;
}
// A function doing nothing ;)
void SampleFunction1()
{
// insert code here
}
// A function always returning zero
int SampleFunction2()
{
// insert code here
return 0;
}
I tried to compile it, and it compiled without any error or warning. But when i tried to use it with the ctyped.cdll.LoadLibrary("library path.dll") in python 3(that actually should work like the C function), it said that it wasn't a valid win32 application. Both python and code::blocks are 32 bit (code:blocks compile with gcc, and i tryed to use an installed version of mingw on my system, but it gives some error about a missing library) while i'm working on win 7 64bit
Do you know what the problem can be, or if i'm doing something wrong?
EDIT1:
i'm on windows 7 64bit, in the specs file of the compiler is wrote: "Thread model: win32, gcc version 3.4.5 (mingw-vista special r3)"
and i used as command
gcc.exe -shared -o library.dll library.c
in python i used
from ctypes import *
lib = cdll.LoadLibrary("C:\\Users\\Francesco\\Desktop\\C programmi\\Python\\Ctypes DLL\\library.dll")
and the error was
WindowsError: [Error 193] %1 is not a valid Win32 application
i installed both python3.1 and mingw from the binary package and not compiling them on my system
EDIT2:
After reading Marc answer.
main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#include <windows.h>
#ifdef BUILD_DLL
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
DLL_EXPORT int MySimpleSum(int A, int B);
#ifdef __cplusplus
}
#endif
#endif // __MAIN_H__
main.c
#include "main.h"
// a sample exported function
DLL_EXPORT int MySimpleSum(int A, int B)
{
return A+B;
}
compiling options
gcc -c _DBUILD_DLL main.c
gcc -shared -o library.dll main.o -Wl,--out-implib,liblibrary.a
with gcc 4.5.2
still get the same error..
I believe in the windows environment you need to use the __declspec annotation. How to create a shared library and the use of __declspec is described here: DLL Creation in MingW.

Resources