%%%begin-myprojects \documentclass[hyperref={colorlinks=true}]{beamer} \usepackage{fancyvrb,relsize} \usepackage{graphicx} \setbeamertemplate{navigation symbols}{} %\usetheme{Boadilla} %\usetheme{CambridgeUS} %\usetheme{Malmoe} %\usetheme{Singapore} %\usetheme{boxes} %\usecolortheme{crane} %\usecolortheme{dove} \usecolortheme{seagull} % very cool with \usetheme{default} %\usefonttheme{professionalfonts} %\useinnertheme{rectangles} \mode \title{MK-CONFIGURE (MK-C) -- lightweight, easy to use alternative for GNU Autotools} \author{Aleksey Cheusov \\ \texttt{vle@gmx.net}} \date{Minsk, Belarus, 2012} \begin{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newenvironment{Code}[1]% {\Verbatim[label=\bf{#1},frame=single,% fontsize=\small,% commandchars=\\\{\}]}% {\endVerbatim} %\newenvironment{Code}[1]% % {\semiverbatim[]}% % {\endsemiverbatim} \newenvironment{CodeNoLabel}% {\Verbatim[frame=single,% fontsize=\small,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{CodeNoLabelSmallest}% {\Verbatim[frame=single,% fontsize=\footnotesize,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{CodeLarge}% {\Verbatim[frame=single,% fontsize=\large,% commandchars=\\\{\}]}% {\endVerbatim} %\newcommand{\prompt}[1]{\textcolor{blue}{#1}} %\newcommand{\prompt}[1]{\textbf{#1}\textnormal{}} \newcommand{\prompt}[1]{{\bf{#1}}} %\newcommand{\h}[1]{\textbf{#1}} %\newcommand{\h}[1]{\bf{#1}\textnormal{}} \newcommand{\h}[1]{{\bf{#1}}} \newcommand{\URL}[1]{\textbf{#1}} \newcommand{\AutohellFile}[1]{\textcolor{red}{#1}} \newcommand{\MKCfile}[1]{\textcolor{green}{#1}} \newcommand{\ModuleName}[1]{\textbf{#1}\textnormal{}} \newcommand{\ProgName}[1]{\textbf{#1}\textnormal{}} \newcommand{\ProjectName}[1]{\textbf{#1}\textnormal{}} \newcommand{\PackageName}[1]{\textbf{#1}\textnormal{}} \newcommand{\MKC}[1]{\large\textsf{#1}\textnormal{}\normalsize} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% \begin{frame} %% \frametitle{qqq} %% \begin{code}{files in the directory} %% bla bla bla %% \end{code} %% \end{frame} %%%end-myprojects %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \titlepage \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \frametitle{About this presentation} \begin{block}{} \begin{itemize} \item It is a part of official documentation. Latest version is available for download from here\\ \URL{http://mova.org/\~{}cheusov/pub/mk-c/mk-c.pdf} % \item % \URL{http://sourceforge.net/projects/mk-configure} \\ % \URL{http://freshmeat.net/projects/mk-configure} \item part 1: Introduction \item part 2: A number of samples of use \item part 3: More complete list of features, TODO and more. \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \frametitle{Concepts behind mk-configure} \begin{block}{Design principles and goals} \begin{itemize} \item \h{I detest code generation} as in Autotools and CMake!\\ \h{Library approach} is used instead. \item Written in \h{bmake}, portable version of \h{NetBSD make(1)}, and UNIX tools. \h{No heavy dependencies} like python, ruby and perl. As a programming language bmake is not as powerful as RuPyPe, but\\ \h{\mbox{bmake+sh} is good enough} for this task. \item Basic principles are \h{similar to traditional \mbox{bsd.*.mk} files}. Actually mk-c contains heavily reworked Mk files from NetBSD. \item \h{Portability} to all UNIX-like systems. \item KISS. Only about 4000 lines of code. \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \frametitle{Concepts behind mk-configure} \begin{block}{Design principles and goals} \begin{itemize} \item mk-configure is not only for end-users and packagers but for developers too. So, one of the main goals is to provide a convenient \h{tool for development}. \item Declarative approach of writing Makefile(s). Build and installation process is controlled with a help of special variables and bmake's include files. \item \h{Cross-compilation}. \item \h{Extensibility}. Extensions to mk-configure are implemented using bmake include files and standard UNIX tools, i.e. shell, awk, sed, grep etc. when needed. \item MK-C is \h{Easy to use}. Only one command is needed to build a project --- \h{mkcmake}. \h{Only Makefile(s)} are needed for specifying build instructions. \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \frametitle{Concepts behind mk-configure} \begin{block}{Negative side-effects} \begin{itemize} \item End-users/packagers have to install bmake and mk-configure to build applications based on mk-configure. \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: Hello world application} \begin{block}{Source code} \begin{Code}{Makefile} PROG = hello .include <\h{mkc.prog.mk}> \end{Code} \begin{Code}{hello.c} #include int main (int, char **) \{ puts ("Hello World!"); return 0; \} \end{Code} % \end{columns} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: Hello world application} % \begin{block} \begin{block}{How it works} \begin{CodeNoLabel} \prompt{\$ export PREFIX=/usr SYSCONFDIR=/etc} \prompt{\$ mkcmake} checking for compiler type... gcc checking for program cc... /usr/bin/cc cc -c hello.c cc -o hello hello.o \prompt{\$ ./hello} Hello World! \prompt{\$ DESTDIR=/tmp/fakeroot mkcmake install} for d in \_ /tmp/fakeroot/usr/bin; do test "\$d" = \_ || install -d "\$d"; done install -c -s -o cheusov -g users -m 755 hello /tmp/fakeroot/usr/bin/hello \prompt{\$} \end{CodeNoLabel} \end{block} Supported targets: all, clean, cleandir (distclean), install, uninstall, installdirs, depend etc. % \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 2: Application using non-standard strlcpy(3)} \begin{block}{Source code} % files \begin{Code}{files in the directory} \prompt{\$ ls -l} total 12 -rw-r--r-- 1 cheusov users 158 May 2 15:04 Makefile -rw-r--r-- 1 cheusov users 187 May 2 15:05 main.c -rw-r--r-- 1 cheusov users 332 May 2 15:09 \h{strlcpy.c} \prompt{\$} \end{Code} % Makefile \begin{Code}{Makefile} PROG = strlcpy_test SRCS = main.c \h{MKC\_SOURCE\_FUNCLIBS} = strlcpy \h{MKC\_CHECK\_FUNCS3} = strlcpy:string.h .include \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 2: Application using non-standard strlcpy(3)} \begin{block}{Source code} \begin{Code}{main.c} #include #ifndef \h{HAVE\_FUNC3\_STRLCPY\_STRING\_H} size_t strlcpy(char *dst, const char *src, size_t siz); #endif int main (int argc, char** argv) \{ /* Use strlcpy(3) here */ return 0; \} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 2: Application using non-standard strlcpy(3)} \begin{block}{How it works on Linux} \begin{CodeNoLabel} \prompt{\$ CC=icc mkcmake} checking for compiler type... \h{icc} checking for function strlcpy... \h{no} checking for func strlcpy ( string.h )... \h{no} checking for program icc... /opt/intel/cc/10.1.008/bin/icc icc -c main.c icc -c strlcpy.c icc -o strlcpy_test main.o \h{strlcpy.o} \prompt{\$ echo \_mkc\_*} _mkc_compiler_type.err _mkc_compiler_type.res _mkc_func3_strlcpy_string_h.c _mkc_func3_strlcpy_string_h.err _mkc_func3_strlcpy_string_h.res _mkc_funclib_strlcpy.c _mkc_funclib_strlcpy.err _mkc_funclib_strlcpy.res _mkc_prog_cc.err _mkc_prog_cc.res \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 2: Application using non-standard strlcpy(3)} \begin{block}{How it works on NetBSD} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... gcc checking for function strlcpy... \h{yes} checking for func strlcpy ( string.h )... \h{yes} checking for program cc... /usr/bin/cc cc -D\h{HAVE\_FUNC3\_STRLCPY\_STRING\_H}=1 -c main.c cc -o strlcpy_test main.o \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: Application using plugins} \begin{block}{Source code} \begin{Code}{Makefile} PROG = myapp \h{MKC\_CHECK\_FUNCLIBS} = dlopen:dl .include <\h{mkc.configure.mk}> .if $\{\h{HAVE\_FUNCLIB.dlopen}:U0\} || \ {} $\{\h{HAVE\_FUNCLIB.dlopen.dl}:U0\} CFLAGS += -DPLUGINS_ENABLED=1 .endif .include \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: Application using plugins} \begin{block}{How it works on QNX} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... gcc checking for function dlopen ( \h{-ldl} )... \h{yes} checking for function dlopen... \h{no} checking for program gcc... /usr/qnx650/host/qnx6/x86/usr/bin/gcc gcc \h{-DPLUGINS\_ENABLED=1} -c myapp.c gcc -o myapp myapp.o \h{-ldl} \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: Application using plugins} \begin{block}{How it works on OpenBSD} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... gcc checking for function dlopen ( \h{-ldl} )... \h{no} checking for function dlopen... \h{yes} checking for program cc... /usr/bin/cc cc \h{-DPLUGINS\_ENABLED=1} -c myapp.c cc -o myapp myapp.o \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 4: Support for shared libraries and C++} \begin{block}{Source code} \begin{Code}{Makefile} LIB = foobar SRCS = foo.\h{cc} bar.\h{cc} baz.\h{cc} MKPICLIB ?= no MKSTATICLIB ?= no \h{SHLIB\_MAJOR} = 1 \h{SHLIB\_MINOR} = 0 .include <\h{mkc.lib.mk}> \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 4: Support for shared libraries} \begin{block}{How it works on Solaris with SunStudio compiler} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... \h{sunpro} checking for program CC... /opt/SUNWspro/bin CC -c \h{-KPIC} foo.cc -o foo.os CC -c \h{-KPIC} bar.cc -o bar.os CC -c \h{-KPIC} baz.cc -o baz.os building shared foobar library (version \h{1.0}) CC \h{-G} \h{-h libfoobar.so.1} -o libfoobar.so.1.0 foo.os bar.os baz.os ln -sf libfoobar.so.1.0 libfoobar.so ln -sf libfoobar.so.1.0 libfoobar.so.1 \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 4: Support for shared libraries} \begin{block}{How it works on Darwin} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... gcc checking for program c++... /usr/bin/c++ c++ -c \h{-fPIC -DPIC} foo.cc -o foo.os c++ -c \h{-fPIC -DPIC} bar.cc -o bar.os c++ -c \h{-fPIC -DPIC} baz.cc -o baz.os building shared foobar library (version 1.0) c++ \h{-dynamiclib -install\_name} /usr/local/lib/libfoobar.1.0.\h{dylib} \h{-current\_version 2.0 -compatibility\_version 2} -o libfoobar.1.0.dylib foo.os bar.os baz.os ln -sf libfoobar.1.0.dylib libfoobar.dylib ln -sf libfoobar.1.0.dylib libfoobar.1.dylib \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 4: Support for shared libraries (Exported symbols)} \begin{block}{} \begin{CodeNoLabel} \prompt{\$ cat Makefile} LIB = foo INCS = foo.h \h{EXPORT\_SYMBOLS} = foo.sym SHLIB_MAJOR = 1 MKSTATICLIB = no .include \prompt{\$ mkcmake} awk 'BEGIN \{print "\{ global:"\} \{print \$0 ";"\} END \{print "local: *; \};"\}' foo.sym > foo.sym.tmp1 && mv foo.sym.tmp1 foo.sym.tmp cc -I. -c -fPIC -DPIC foo.c -o foo.os building shared foo library (version 1) ld -shared -soname libfoo.so.1 \h{--version-script foo.sym.tmp} -o libfoo.so.1 foo.os \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Dependency graph for all subprojects} This project consists of several subprojects: dict, dictd, dictfmt, dictzip, libdz, libmaa and libcommon. libcommon contains common code for executables and should not be installed. \begin{figure} \includegraphics[width=\textwidth, height=0.50\textheight, keepaspectratio=false]{dep_graph.eps} \end{figure} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Files and directories} \begin{CodeNoLabel} \prompt{\$ ls -l} total 4 drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 dict drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 dictd drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 dictfmt drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 dictzip drwxr-xr-x 2 cheusov users 1 Jan 26 12:03 doc drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 libcommon drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 libdz drwxr-xr-x 2 cheusov users 1 Jan 26 12:01 libmaa -rw-r--r-- 1 cheusov users 306 Jan 26 12:03 \h{Makefile} \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Source code} \begin{Code}{Makefile} SUBPRJ = libcommon:dict # dict depends on libcommon SUBPRJ += libcommon:dictd SUBPRJ += libcommon:dictzip SUBPRJ += libcommon:dictfmt SUBPRJ += libmaa:dict SUBPRJ += libmaa:dictd SUBPRJ += libmaa:dictfmt SUBPRJ += libmaa:dictzip SUBPRJ += libdz:dictzip SUBPRJ += doc .include <\h{mkc.subprj.mk}> \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Source code} \begin{Code}{libcommon/Makefile} # Internal static library that implements functions # common for dict, dictd, dictfmt and dictzip applications LIB = common SRCS = str.c iswalnum.c # and others \h{MKINSTALL} = no # Do not install internal library! .include \end{Code} \begin{Code}{libcommon/linkme.mk} PATH.common := \$\{.PARSEDIR\} CPPFLAGS += -I\$\{PATH.common\}\h{/include} DPLIBDIRS += \$\{PATH.common\} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Source code} \begin{Code}{libmaa/Makefile} LIB = maa SRCS = set.c prime.c log.c # etc. \h{INCS} = maa.h SHLIB_MAJOR = 1 SHLIB_MINOR = 2 SHLIB_TEENY = 0 # list of exported symbols \h{EXPORT\_SYMBOLS} = maa.sym .include \end{Code} \begin{Code}{libmaa/linkme.mk} PATH.maa := \$\{.PARSEDIR\} CPPFLAGS += -I\$\{PATH.maa\} DPLIBDIRS += \$\{PATH.maa\} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Source code} \begin{Code}{libmaa/maa.sym} hsh_create hsh_destroy hsh_insert hsh_delete hsh_retrieve ... lst_create lst_destroy lst_insert ... set_create set_destroy set_add set_union ... \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Source code} \begin{Code}{libdz/Makefile} LIB = dz SRCS = dz.c INCS = dz.h \h{MKC\_REQUIRE\_HEADERS} = zlib.h \h{MKC\_REQUIRE\_FUNCLIBS} = deflate:z EXPORT_SYMBOLS = dz.sym SHLIB_MAJOR = 1 SHLIB_MINOR = 0 LDADD = -lz .include \end{Code} \begin{Code}{libdz/linkme.mk} PATH.dz := \$\{.PARSEDIR\} CPPFLAGS += -I\$\{PATH.dz\} DPLIBDIRS += \$\{PATH.dz\} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{Source code} \begin{Code}{dictzip/Makefile} PROG = dictzip MAN = dictzip.1 \h{.include} "../libcommon/linkme.mk" \h{.include} "../libdz/linkme.mk" \h{.include} "../libmaa/linkme.mk" DPLIBS += -lcommon -ldz -lmaa .include \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{How it fails ;-)} \begin{CodeNoLabel} \prompt{\$ mkcmake errorcheck-dictzip} ================================================== errorcheck ===> \h{libcommon} ... errorcheck ===> \h{libmaa} ... ================================================== errorcheck ===> \h{libdz} checking for header zlib.h... \h{no} checking for function deflate ( -lz )... \h{no} checking for function deflate... \h{no} \h{ERROR: cannot find header zlib.h} \h{ERROR: cannot find function deflate:z} ... \prompt{\$ echo \$?} 1 \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: Big project consisting of several subprojects} \begin{block}{How it works} \begin{CodeNoLabel} \prompt{\$ mkcmake dictzip} ... ================================================== all ===> \h{libdz} ... checking for header zlib.h... \h{yes} checking for function deflate ( -lz )... \h{yes} ... ================================================== all ===> \h{dictzip} ... cc \h{-I../libcommon -I../libdz -I../libmaa} -c dictzip.c cc \h{-L/tmp/hello\_dictd/libcommon -L/tmp/hello\_dictd/libdz} \h{-L/tmp/hello\_dictd/libmaa} -o dictzip dictzip.o -lcommon -lmaa -ldz \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 6: Support for Lua programming language} \begin{block}{Source code} \begin{Code}{Makefile} SCRIPTS = foobar # scripts written in Lua LUA\_LMODULES = foo bar # modules written in Lua LUA\_CMODULE = baz # Lua module written in C .include \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 6: Support for Lua programming language} \begin{block}{How it works} \begin{CodeNoLabel} \prompt{\$ mkcmake errorcheck} checking for program pkg-config... /usr/pkg/bin/pkg-config checking for [pkg-config] lua... 1 (yes) checking for [pkg-config] lua --cflags... -I/usr/pkg/include checking for [pkg-config] lua --libs... -Wl,-R/usr/pkg/lib -L/usr/pkg/lib -llua -lm checking for [pkg-config] lua --variable=INSTALL_LMOD... /usr/pkg/share/lua/5.1 checking for [pkg-config] lua --variable=INSTALL_CMOD... /usr/pkg/lib/lua/5.1 checking for compiler type... gcc checking for header lua.h... yes checking for program cc... /usr/bin/cc \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 6: Support for Lua programming language} \begin{block}{How it works} \begin{CodeNoLabel} \prompt{\$ export PREFIX=/usr/pkg} \prompt{\$ mkcmake all} cc -DHAVE_HEADER_LUA_H=1 -I/usr/pkg/include -c -fPIC -DPIC baz.c -o baz.os building shared baz library (version 1.0) cc -shared -Wl,-soname -Wl,libbaz.so.1 -o baz.so baz.os -Wl,-R/usr/pkg/lib -L/usr/pkg/lib -llua -lm \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 6: Support for Lua programming language} \begin{block}{How it works} \begin{CodeNoLabel} \prompt{\$ mkcmake install DESTDIR=/tmp/fakeroot} ... \prompt{\$ find /tmp/fakeroot -type f} /tmp/fakeroot/usr/pkg/bin/foobar /tmp/fakeroot/usr/pkg/lib/lua/5.1/baz.so /tmp/fakeroot/usr/pkg/share/lua/5.1/foo.lua /tmp/fakeroot/usr/pkg/share/lua/5.1/bar.lua \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 7: Custom tests and sizeof of system types} \begin{block}{Source code} \begin{Code}{Makefile} MKC\_CUSTOM\_DIR = \h{\$\{.CURDIR\}/checks} # m4 supports -P flag (GNU, NetBSD) M4 ?= m4 # overridable (\h{gm4}) MKC\_REQUIRE\_CUSTOM += m4P MKC\_CUSTOM\_FN.m4P = \h{m4P.sh} .export: M4 # \_\_attribute ((\{con,de\}structor)) MKC\_REQUIRE\_CUSTOM += \h{constructor destructor} # sizeof MKC\_CHECK\_SIZEOF = char short int long void* long-long LIB = mylib CFLAGS += -DM4\_CMD='"\$\{M4\}"' .include \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 7: Custom tests and sizeof of system types} \begin{block}{Source code} \begin{Code}{Files in checks/ subdirectory} \prompt{\$ ls checks/} constructor.c destructor.c m4P.sh \prompt{\$} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 7: Custom tests and sizeof of system types} \begin{block}{Source code} \begin{Code}{checks/m4P.sh} #!/bin/sh input ()\{ cat <<'EOF' m4\_define(fruit, apple) fruit EOF \} M4=\$\{M4-m4\} if input | \$\{M4\} -P | grep \^{}apple > /dev/null; then echo 1 else echo 0 fi \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 7: Custom tests and sizeof of system types} \begin{block}{Source code} \begin{Code}{checks/constructor.c} void __attribute ((constructor)) dummy (void) \{ \} \end{Code} \begin{Code}{checks/destructor.c} void __attribute ((destructor)) dummy (void) \{ \} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 7: Custom tests and sizeof of system types} \begin{block}{How it works on FreeBSD} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... gcc checking for sizeof char... \h{1} checking for sizeof short... \h{2} checking for sizeof int... \h{4} checking for sizeof long... \h{4} checking for sizeof void*... \h{4} checking for sizeof long long... \h{8} checking for custom test \h{m4P... 0 (no)} checking for custom test \h{constructor}... \h{1 (yes)} checking for custom test \h{destructor}... \h{1 (yes)} checking for program cc... /usr/bin/cc \h{ERROR: custom test m4P failed} *** Error code 1 ... \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 7: Custom tests and sizeof of system types} \begin{block}{How it works on FreeBSD with GNU m4} \begin{CodeNoLabel} \prompt{\$ M4=gm4 mkcmake} checking for compiler type... gcc checking for sizeof char... 1 checking for sizeof short... 2 checking for sizeof int... 4 checking for sizeof long... 4 checking for sizeof void*... 4 checking for sizeof long long... 8 checking for custom test \h{m4P... 1 (yes)} checking for custom test constructor... 1 (yes) checking for custom test destructor... 1 (yes) checking for program cc... /usr/bin/cc ... \prompt{\$} \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 8: Portable version of AWK from NetBSD} \begin{block}{http://mova.org/\~{}cheusov/pub/mk-configure/nbawk/} \begin{Code}{Makefile (part 1)} PROG = awk SRCS = awkgram.y b.c lex.c lib.c main.c parse.c proctab.c run.c tran.c YHEADER = yes MKC\_COMMON\_DEFINES.Linux = -D\_GNU\_SOURCE MKC\_COMMON\_HEADERS = ctype.h stdio.h string.h MKC\_CHECK\_FUNCS1 = \_\_fpurge:stdio\_ext.h fpurge isblank MKC\_CHECK\_FUNCS3 = strlcat MKC\_SOURCE\_FUNCLIBS = fpurge strlcat WARNS= 4 WARNERR= no # do not treat warnings as errors MKC\_REQD= 0.19.0 # mk-configure>=0.19.0 is required ... # to be continued on the next slide \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 8: Portable version of AWK from NetBSD} \begin{block}{http://mova.org/\~{}cheusov/pub/mk-configure/nbawk/} \begin{Code}{Makefile (part 2)} ... # beginning is on the previous slide \h{.include} \h{.if} \$\{HAVE\_FUNC1.isblank:U0\} CPPFLAGS += -DHAS\_ISBLANK \h{.endif} \h{.if} !\$\{HAVE\_FUNC1.fpurge:U1\} && !\$\{HAVE_FUNC1.\_\_fpurge.stdio\_ext\_h:U1\} MKC\_ERR\_MSG+= "fpurge(3) cannot be found" \h{.endif} CPPFLAGS += -I. LDADD += -lm \h{.include} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 8: Portable version of AWK from NetBSD} \begin{block}{run.c} \begin{CodeNoLabelSmallest} --- nbawk-20100903/run.c.orig +++ nbawk-20100903/run.c @@ -40,6 +40,14 @@ #include "awk.h" #include "awkgram.h" +#ifndef HAVE_FUNC1_FPURGE +int fpurge (FILE *stream); +#endif + +#ifndef HAVE\_FUNC3\_STRLCAT +size\_t strlcat(char *dst, const char *src, size_t size); +#endif + #define tempfree(x) if (istemp(x)) tfree(x); else void stdinit(void); \end{CodeNoLabelSmallest} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 8: Portable version of AWK from NetBSD} \begin{block}{fpurge.c} \begin{CodeNoLabelSmallest} #include #if HAVE\_FUNC1\_\_\_FPURGE\_STDIO\_EXT\_H #include #endif int fpurge(FILE *stream); int fpurge(FILE *stream) \{ #if HAVE\_FUNC1\_\_\_FPURGE\_STDIO\_EXT\_H \_\_fpurge (stream); return 0; #else #error "cannot find fpurge(3), sorry" #endif \} \end{CodeNoLabelSmallest} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 8: Portable version of AWK from NetBSD} \begin{block}{strlcpy.c} \begin{CodeNoLabel} If you need this code, you know where to get it from! ;-) \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 8: Portable version of AWK from NetBSD} % \begin{block} \begin{block}{How it works on Linux} \begin{CodeNoLabel} \prompt{\$ mkcmake} checking for compiler type... gcc checking for function fpurge... \h{no} checking for function strlcat... \h{no} checking for func __fpurge ( stdio_ext.h )... \h{yes} checking for func fpurge... \h{no} checking for func isblank... \h{yes} checking for func strlcat... \h{no} checking for program yacc... \h{/usr/bin/yacc} ... cc \h{-Wall -Wstrict-prototypes ...} -I. \h{-D\_GNU\_SOURCE} -c awkgram.c ... cc -o awk awkgram.o ... \h{fpurge.o strlcat.o} -lm \prompt{\$ ./awk} usage: ./awk [-F fs] [-v var=value] [-f progfile | 'prog'] [file ...] \prompt{\$} \end{CodeNoLabel} \end{block} Supported targets: all, clean, cleandir (distclean), install, uninstall, installdirs, depend etc. % \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 9: Cross-compilation} \begin{block}{How it works} \begin{CodeNoLabel} \prompt{\$ export SYSROOT=/tmp/destdir.sparc64} \prompt{\$ export TOOLCHAIN\_PREFIX=sparc64--netbsd-} \prompt{\$ export TOOLCHAIN\_DIR=/tmp/tooldir.sparc64/bin} \prompt{\$ uname -srm} NetBSD 5.99.56 amd64 \prompt{\$ mkcmake} checking for compiler type... gcc /tmp/tooldir.sparc64/bin/sparc64--netbsd-gcc --sysroot=/tmp/destdir.sparc64 -c hello.c -o hello.o /tmp/tooldir.sparc64/bin/sparc64--netbsd-gcc --sysroot=/tmp/destdir.sparc64 -o hello hello.o \prompt{\$ file hello} hello: ELF 64-bit MSB executable, SPARC V9, relaxed memory ordering, (SYSV), dynamically linked (uses shared libs), for NetBSD 5.99.56, not stripped \prompt{\$ } \end{CodeNoLabel} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Features} \begin{block}{} \begin{enumerate} \item Automatic detection of OS features (\ModuleName{mkc.configure.mk}) \begin{itemize} \item \h{header presence} (MKC\_\{CHECK,REQUIRE\}\_HEADERS) \item \h{function declaration} (MKC\_\{CHECK,REQUIRE\}\_FUNCS[n]) \item \h{type declaration} (MKC\_\{CHECK,REQUIRE\}\_TYPES) \item \h{structure member} (MKC\_\{CHECK,REQUIRE\}\_MEMBERS) \item \h{variable declaration} (MKC\_\{CHECK,REQUIRE\}\_VARS) \item \h{define declaration} (MKC\_\{CHECK,REQUIRE\}\_DEFINES) \item \h{type size} (MKC\_CHECK\_SIZEOF) \item \h{function} implementation \h{in the library} (MKC\_\{CHECK,REQUIRE\}\_FUNCLIBS and MKC\_SOURCE\_FUNCLIBS) \item \h{checks for programs} (MKC\_\{CHECK,REQUIRE\}\_PROGS) \item \h{user's custom checks} (MKC\_\{CHECK,REQUIRE\}\_CUSTOM) \item \h{built-in checks} (MKC\_CHECK\_BUILTINS), e.g. endianess, prog\_flex, prog\_bison, prog\_gawk or prog\_gm4) \end{itemize} \end{enumerate} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{Features} \begin{block}{} \begin{enumerate} \setcounter{enumi}{1} \item Building, installing, uninstalling, cleaning etc. Supported targets: \h{all}, \h{install}, \h{uninstall}, \h{clean}, \h{cleandir} (\h{distclean}), \h{installdirs}, \h{depend} and others. \item Building \h{standalone programs} (\ModuleName{mkc.prog.mk}), \h{static, shared and dynamically loaded libraries} (\ModuleName{mkc.lib.mk}) using \h{C}, \h{C++}, \h{Objective C}, \h{Pascal} and \h{Fortran} compilers. Shared libraries support is provided for numerous OSes: \h{NetBSD}, \h{FreeBSD}, \h{OpenBSD}, \h{DragonFlyBSD}, \h{MirOS BSD}, \h{Linux}, \h{Solaris}, \h{Darwin} (MacOS-X), \h{Interix}, \h{Tru64}, \h{QNX}, \h{HP-UX}, \h{Cygwin} (no support for shared libraries and DLLs yet) and compilers: \h{GCC}, \h{Intel C/C++} compilers, \h{Portable C compiler} AKA \h{pcc}, \h{DEC C/C++ compiler}, \h{HP C/C++ compiler}, \h{Oracle SunStudio} and others. \end{enumerate} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{Features} \begin{block}{} \begin{enumerate} \setcounter{enumi}{3} \item Handling \h{man} pages, \h{info} manuals and \h{POD} documents. \item Handling \h{scripts} as well as \h{plain text files}, i.e. installing, uninstalling and handling \h{.in files} (replacing, for example, \h{@bindir@}, \h{@sysconfdir@}, \h{@version@} fragments with real values). \item \h{Cross-compilation}. mk-configure itself doesn't run target system executables, so you can freely use cross-tools (compiler, linker etc.). You can also override/set any variable initialized by mk-configure. \item Support for \h{pkg-config}. \item Support for \h{Lua} programming language. \item Support for \h{yacc} and \h{lex}. \end{enumerate} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{Features} \begin{block}{} \begin{enumerate} \setcounter{enumi}{10} \item Support for projects with multiple subprojects (\ModuleName{mkc.subprj.mk} and \ModuleName{mkc.subdir.mk}). \item Special targets bin\_tar, bin\_targz, bin\_tarbz2, bin\_zip, bin\_deb creates .tar, .tar.gz, .tar.bz2, .zip archives and .deb package (on Debian Linux). \item Parts of mk-configure functionality is accesible via individual programs, e.g. \ProgName{mkc\_install}, \ProgName{mkc\_check\_compiler}, \ProgName{mkc\_check\_header}, \ProgName{mkc\_check\_funclib}, \ProgName{mkc\_check\_decl}, \ProgName{mkc\_check\_prog}, \ProgName{mkc\_check\_sizeof} and \ProgName{mkc\_check\_custom}. \end{enumerate} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{MK-CONFIGURE in real world} \begin{block}{Packagers are welcome! ;-)} \small NetBSD make (bmake) is packaged in the following OSes: \begin{itemize} \item FreeBSD, pkgsrc (NetBSD, DragonFlyBSD...) (\h{devel/bmake}) \item Gentoo Linux, Fedora Linux, AltLinux \item Debian/Ubuntu\\ deb http://mova.org/\~{}cheusov/pub/debian lenny main\\ deb-src http://mova.org/\~{}cheusov/pub/debian lenny main \end{itemize} mk-configure is packaged in the following OSes \begin{itemize} \item FreeBSD, pkgsrc (NetBSD, DragonFlyBSD...) (\h{devel/mk-configure}) \item Debian/Ubuntu\\ deb http://mova.org/\~{}cheusov/pub/debian lenny main\\ deb-src http://mova.org/\~{}cheusov/pub/debian lenny main \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{MK-CONFIGURE in real world} \begin{block}{Real life samples of use} \begin{itemize} \item Lightweight modular malloc Debugger.\\ \URL{http://sourceforge.net/projects/lmdbg/} \URL{http://pkgsrc.se/wip/lmdbg/}\\ \item NetBSD version of AWK programming language, ported to other Operating Systems.\\ \URL{http://mova.org/\~{}cheusov/pub/mk-configure/nbawk/} \item Modules support for AWK programming language\\ \URL{http://sourceforge.net/projects/runawk/} \URL{http://pkgsrc.se/lang/runawk/}\\ \item Tool for distributing tasks over network or CPUs\\ \URL{http://sourceforge.net/projects/paexec/} \URL{http://pkgsrc.se/wip/paexec/}\\ \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{MK-CONFIGURE in real world} \begin{block}{Real life samples of use} \begin{itemize} \item Distributed fault tolerant bulk build tool for pkgsrc\\ \URL{http://mova.org/\~{}cheusov/pub/distbb/}\\ \URL{http://pkgsrc.se/wip/distbb/}\\ \item Client/server package search system for pkgsrc\\ \URL{http://mova.org/\~{}cheusov/pub/pkg\_online/} \URL{http://pkgsrc.se/wip/pkg\_online-client/}\\ \URL{http://pkgsrc.se/wip/pkg\_online-server/}\\ \item Any project based on traditional \ModuleName{bsd.\{prog,lib,subdir\}.mk} can easily be converted to \MKC{mk-configure}. \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%begin-myprojects \begin{frame}[fragile,t] \frametitle{MK-CONFIGURE in real world} \begin{block}{My opensource projects using mk-configure (filled hexagon), Mk files (box) and others (oval)} \begin{figure} \includegraphics[width=\textwidth, height=0.60\textheight, keepaspectratio=false]{my_prjs.eps} \end{figure} % \begin{figure} % \includegraphics[width=0.7\textwidth, height=0.10\textwidth, keepaspectratio=false]{my_prjs2.eps} % \end{figure} \end{block} \end{frame} %%%end-myprojects %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile,t] \frametitle{MK-C needs your help ;-)} \begin{block}{} \begin{itemize} \item Packagers are welcome (Linux distros, OpenBSD etc.) \item MK-C distribution contains \h{a lot of regression tests and samples of use} (samples are used for testing too).\\ \h{Shell accounts} on "exotic" UNIX-like platforms are needed (AIX, HP-UX, non-ELF BSDs, IRIX, Solaris, Hurd etc.) for testing and development. \item Review of the documentation. At the moment only mk-configure(7), samples/ and this presentation are available. \item sf.net provides two mailing lists:\\ \h{mk-configure-help} and \h{mk-configure-discuss}. \item TODO file in the distribution is full of tasks. \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{} \begin{block}{} \begin{center} \Huge{The END.} \end{center} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%begin-myprojects \end{document} %%%end-myprojects