Creating and reusing packages based on Makefiles
Conan can create packages and reuse them with Makefiles. The AutoToolsBuildEnvironment
build helper helps with most of the necessary tasks.
This how-to has been tested in Windows with MinGW and Linux with gcc. It uses static libraries but could be extended to shared libraries too. The Makefiles surely can be improved. They are just an example.
Creating packages
Sources for this example can be found in our examples repository in the features/makefiles folder:
$ git clone https://github.com/conan-io/examples.git
$ cd examples/features/makefiles
$ cd hellolib
It contains a src folder with the source code and a conanfile.py file for creating a package.
Inside the src folder, there is Makefile to build the static library. This Makefile uses
standard variables like $(CPPFLAGS)
or $(CXX)
to build it:
SRC = hello.cpp
OBJ = $(SRC:.cpp=.o)
OUT = libhello.a
INCLUDES = -I.
.SUFFIXES: .cpp
default: $(OUT)
.cpp.o:
$(CXX) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ)
The conanfile.py file uses the AutoToolsBuildEnvironment
build helper. This helper defines
the necessary environment variables with information from dependencies, as well as other variables
to match the current Conan settings (like -m32
or -m64
based on the Conan arch
setting)
from conans import ConanFile, AutoToolsBuildEnvironment
from conans import tools
class HelloConan(ConanFile):
name = "hello"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"
exports_sources = "src/*"
def build(self):
with tools.chdir("src"):
atools = AutoToolsBuildEnvironment(self)
# atools.configure() # use it to run "./configure" if using autotools
atools.make()
def package(self):
self.copy("*.h", dst="include", src="src")
self.copy("*.lib", dst="lib", keep_path=False)
self.copy("*.a", dst="lib", keep_path=False)
def package_info(self):
self.cpp_info.libs = ["hello"]
With this conanfile.py you can create the package:
$ conan create . user/testing -s compiler=gcc -s compiler.version=4.9 -s compiler.libcxx=libstdc++
Using packages
Now let’s move to the application folder:
$ cd ../helloapp
There you can also see a src folder with a Makefile creating an executable:
SRC = app.cpp
OBJ = $(SRC:.cpp=.o)
OUT = app
INCLUDES = -I.
.SUFFIXES: .cpp
default: $(OUT)
.cpp.o:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(OUT): $(OBJ)
$(CXX) -o $(OUT) $(OBJ) $(LDFLAGS) $(LIBS)
And also a conanfile.py very similar to the previous one. In this case adding a requires
and a deploy()
method:
from conans import ConanFile, AutoToolsBuildEnvironment
from conans import tools
class AppConan(ConanFile):
name = "app"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
exports_sources = "src/*"
requires = "hello/0.1@user/testing"
def build(self):
with tools.chdir("src"):
atools = AutoToolsBuildEnvironment(self)
atools.make()
def package(self):
self.copy("*app", dst="bin", keep_path=False)
self.copy("*app.exe", dst="bin", keep_path=False)
def deploy(self):
self.copy("*", src="bin", dst="bin")
Note that in this case, the AutoToolsBuildEnvironment
will automatically set values to CPPFLAGS
,
LDFLAGS
, LIBS
, etc. existing in the Makefile with the correct include directories, library names,
etc. to properly build and link with the hello
library contained in the “hello” package.
As above, we can create the package with:
$ conan create . user/testing -s compiler=gcc -s compiler.version=4.9 -s compiler.libcxx=libstdc++
There are different ways to run executables contained in packages, like using virtualrunenv
generators.
In this case, since the package has a deploy()
method, we can use it:
$ conan install app/0.1@user/testing -s compiler=gcc -s compiler.version=4.9 -s compiler.libcxx=libstdc++
$ ./bin/app
$ Hello World Release!