tmk Tips

Last update of this Page:


Contents


Configuration


Small Utilities

How to clean-up core *~ etc. files.

I want to delete core file and editor backup file with ``tmk clean''.

Add next code at your TMakefile (or TMakefile.proj). (Ref:: ``tmk tutorial'', Chapter 3, Target clean) In this example, backup file name is assumed as *~ like Emacs.

#
# core and backup clean
#
target core_bk_clean ALWAYS_BUILD {
    set deletebakupfile [glob -nocomplain *~]
    append deletebakupfile " core a.out TAGS"
    puts -nonewline "file delete -- "
    foreach f ${deletebakupfile} {
	file delete -force -- ${f}
	puts -nonewline "${f} "
    }
    puts ""
}
depend clean core_bk_clean

How to make TAGS file with ``tmk tags''.

Use module tags. And type % tmk tags

 module { tags }
 

I want to make .eps file from .png with convert.

Here is a way to convert all *.png files to to *.eps with tmk and convert.

Sometimes, I want to convert files with convert command like next Makefile.

# -- Makefile --
.png.eps:
	convert $< $*.eps
.SUFFIXES .png .eps
 

Next is such code, but depends on convert command.

#
# make_convert_rule with listed files
#
proc make_convert_rule { orig_suffix target_suffix file_list } {
    puts "make_suffix_rule: from $orig_suffix -> $target_suffix with $file_list"
    foreach one_source $file_list {
	if { [regsub $orig_suffix $one_source $target_suffix tmp] } {
	    target $tmp $one_source {
		cmd convert ${SRC} ${TAIL}
	    }
	    build $tmp
	} else {
	    puts "$one_source is no suffix $orig_suffix, ignored."
	}
    }
}
#
# all files
#
proc make_convert_rule { orig_suffix target_suffix } {
    set allfile [glob -nocomplain "*$orig_suffix" ]
    make_convert_rule_with_list $orig_suffix $target_suffix $allfile
}
 

If you want to convert some specified file like a.png, b.png and c.png to a.eps, b.eps and c.eps, next line will help you.

 make_convert_rule_with_list .png .eps { a.png b.png c.png }
 

However, in the tmk manner, you want to all *.png to *.eps, just say:

 make_convert_rule .png .eps
 

But clean is not so easy. I think you sometimes make some file with special suffix like *.eps directory. Then just rm *.eps is very dangerous.



Just Small Tips


How to process tmk recursively for subdirectories.

Write subdir in your TMakefile.

Example 1

# proceed in all subdirs
subdir [glob -nocomplain *]

Example 2

# proceed specified subdirs `foo' and `bar'
subdir "foo bar"

How to do not make executable but make shared lib.

Q: I commented out the main function, but tmk detects that main function and tries to generate an executable. Then fail the compilation. How can I avoid that?

A: Most easy way is that Just delete main functions which you do not need anymorefrom your source or use other function name. However, usually I just want to comment it out.

tmk detects main function by a regex. So, if you delete main function by some macros, sometimes tmk do not know that the main function is deleted. Then, tmk tries to generate an executable. But main is gone in fact, then you fail the compilation.

To avoid this, (for the C++ module (cxx)) write the next lines in your TMakefile.

 # automatic main function detection is deactivated.
 set ::cxx::DETECT_EXE 0
 

However, this case, no executable will be generated in this directory. If you do not need to link some functions in a file (say foo.C). Write line next lines in your TMakefile.

 # I do not want to compile this file.
 lappend EXCLUDE foo.C
 

Remove an element from a list

Sometimes I want to remove an element from a list in project. To temporarily disable the someone's setting. For example, I want to remove an element -Wno-uninitialize from cxx::FLAGS. In such case, you can use this function:

#
# delete with !=
#
proc delete { element list } {
    set _delete_tmp ""
    while { [ llength $list ] > 0 } {
	# (car list) = [lrange $list 0 0]
        if { [lrange $list 0 0] != $element } {
	    # puts "DEBUG: append [lrange $list 0 0]"
	    lappend _delete_tmp [lrange $list 0 0]
	}
	# (cdr list) = [lrange $list 1 end]
	set list [lrange $list 1 end]
    }
    return $_delete_tmp
}
 

Example of deleting the element -Wno-uninitialize from cxx::FLAGS is:

 set cxx::FLAGS [ delete -Wno-uninitialize ${cxx::FLAGS} ]
 

Link module


link other project 1, The other project location is in the same directory to my project.

When you have the next directory structure.

all_projdir +---+ GMU    --- WidgetLib
                + myproj --- test1 -+-- myprog.C
                                    +-- TMakefile

And you want to build a program from myprog.C with GMU/WigetLib's library. GMU/WigetLib should be build with tmk. Put next line to your all_projdir/myproj/test1/TMakefile.

#------------------------------------------------------------
# TMakefile
#------------------------------------------------------------
lappend link::PROJLIBS GMU/WidgetLib

Then tmk knows the link name and the directories.


link other project 2, The other project is somewhere no related with my project.

When you have the next directory structure.

/somedir  +--- somewhere +--- project1 +--- lib1  +--- libproj1lib1.so
          |                            +--- include
          |
          +--- allmyproj +--- myproj   +--- prog2 +--- myprog.C
                                                  +--- TMakefile

The other project library is /somedir/somewhere/project1/lib1/libproj1lib1.so. You want to link it with myprog.C.

There are several ways. One is using link::LIBPATH and link::SYSLIBS with /somedir/allmyproj/myproj/prog2/TMakefile. (recommended)

#------------------------------------------------------------
# TMakefile
#------------------------------------------------------------
#
# where is the other project top dir : full path
#
set OTHERPROJECTDIR /somedir/somewhere/project1

#
# add include directory for compile
#
lappend cxx::FLAGS -I${OTHERPROJECTDIR}/include

#
# add the link path.
#
lappend link::LIBPATH ${OTHERPROJECTDIR}/lib1

#
# add the linking library.
#
lappend link::SYSLIBS projlib1

Or, tell library to ld directory.

#------------------------------------------------------------
# TMakefile
#------------------------------------------------------------
#
# where is the other project top dir : full path
#
set OTHERPROJECTDIR /somedir/somewhere/project1

#
# add include directory for compile
#
lappend cxx::FLAGS -I${OTHERPROJECTDIR}/include

#
# which library do you want to link, exactly
#
set LIBDIR      ${OTHERPROJECTDIR}/lib1

#
# according to the gcc document, this must be right, but not works...
#
# lappend link::FLAGS -Xlinker -rpath -Xlinker ${LIBDIR} -lproj1lib1

#
# set the library directory with full pathname.
#
lappend link::FLAGS ${LIBDIR}/libprojlib1.so

link to main project

You have a directory which is not under the main project, but you want to link to main project's library.

This is not so good situation, since main projet should be one. However, there is a main project and just you want to test some library. Then, you can put PROJROOT as follows.

#------------------------------------------------------------
# TMakefile
#------------------------------------------------------------
set PROJROOT /your/main/projectroot

make a static linked object

You can make a static linked object with setting next option of link module. However, you should recompile all. You can check the all libraries are statically linked by command ldd (on Linux). Usually, system libraries are not linked statically. If you want to link all system libraries statically, you should specified system static libraries.

set link::MAKE_SHLIB 0
set link::MAKE_LIB   1
set link::LINK_MODE "static"

It seems ld prefers link to shared library if it exists. So, you need to remove all .so files you created. Then for the whole project, you can use TMakefile.priv for this purpose.

You can check your executable is statically linkd or not with the command ldd your_exe_file.

I encountered a strange problem. We linked all library twice since we do not know the order. But, once I had an experience which is not enough for in some case. But I did not understand. I just change the PROJLIB's order (the basic one is later at the TMakefile to make sure), then it works, like next example.

# QtWidgets depends on util
# But this once failed in static link library.
lappend link::PROJLIBS base/util
lappend link::PROJLIBS base/QtWidgets
# This is safer. But tmk has already assumed this situation.
# But this works in a case of static linking.
lappend link::PROJLIBS base/QtWidgets
lappend link::PROJLIBS base/util

gcc 4.5.x or higher linker option

gcc 4.5.x passes --as-needed linker option by default, this gives you some missing symbol when your program linked shared library that implicitly linked shared library. For instance,my program links foo.so and foo.so links libutil.so when I created foo.so, then I got the following undefined reference errors.

  libutil.so: undefined reference to `dlopen'
  libutil.so: undefined reference to `dlclose'
  libutil.so: undefined reference to `dlerror'
  libutil.so: undefined reference to `dlsym'
Solving this problem, add --no-as-needed linker flag. For tmk,
  append  link::FLAGS "-Wl,--no-as-needed"
in TMakefile.proj, for instance.

For a package creation, this default setting removes dependency, therefore, this default makes sense. However, this is a difficult problem.

See http://wiki.debian.org/ToolChain/DSOLinking


Tcl memo


#------------------------------------------------------------
# how to get/set the environment variable
#------------------------------------------------------------
set environment_var_of_HOME $env(HOME)

#------------------------------------------------------------
# when you have not $HOME, maybe you can not write
#------------------------------------------------------------
set $env(HOME) "/my/home/"

#------------------------------------------------------------
# run a command
#------------------------------------------------------------
# run a command 1
#
set datestr "[ exec date ]"
#
# run a command 2 ... when you've got a command as a list
#
set cmd "{date}"
set datestr "[ eval exec ${cmd} ]"

#------------------------------------------------------------
# How to get the OS type, platform information
# ... This is in a tclvars. There is many information you can get.
# See tclvars.
#------------------------------------------------------------
# array variable tcl_platform gives you platform, os, osVersion, user, etc..
#
puts $tcl_platform(platform) 	# windows, unix, macintosh, ...
puts $tcl_platform(os)       	# Linux, IRIX, SunOS, ...
puts $tcl_platform(osVersion)   # e.g., 2.4.26.1.p4 on my Linux


tmk with Emacs


How to use tmk with compilation-mode

Q1: I want to change compile command to tmk from make -k.

A1: Add next code to your .emacs file.

(setq compile-command "tmk ")

However, the effect of above code is global. Then,

Q2: I want to set compile command to tmk, if and only if I am in c-mode (c++-mode) and there is a TMakefile in the current directory.

A2: In the case of C or C++, you can set c-mode-common-hook for customizing your mode. Next code is effective when

Most of emacs mode always provides a hook function like this. So, you may be able to customize your mode in this way.

(defun my-cpp-mode-common-hook ()
  (progn
     ;; you can write other customizations for your C(C++) mode
     (if (file-exists-p "TMakefile")
	(set (make-local-variable 'compile-command) "tmk "))))
(add-hook 'c-mode-common-hook 'my-cpp-mode-common-hook)

How to change the emacs major mode when a *.tmk or a TMakefile is read?

Q: When I read a tmk module (*.tmk file) or a TMakefile (TMakefile*), I want to change my emacs major mode to the tcl-mode. How to do it?

A: Add next code to your .emacs.

(setq auto-mode-alist
      (append
       (list '("\\.tmk$" .  tcl-mode)
	     '("TMakefile.*$" .  tcl-mode))
       auto-mode-alist))

How to jump to error line with tmk and compilation-mode.

Q: I tmked on the top of my project. In that case, emacs can not jump to an error line. Can you help me?

A: Current tmk prints `in directory' and `back in directory' when it changes the directory instead of `Entering directory' and `Leaving directory' of GNU make. Then, you should teach this to emacs. Add next code to your .emacs file.

(progn
  (defun my-compilation-mode-hook ()
    (setq compilation-enter-directory-regexp
	  "[^\n]*: in directory \\([^\n]*\\)$")
    (setq compilation-leave-directory-regexp
	  "[^\n]*: back in directory \\([^\n]*\\)$")
    )
  (add-hook 'compilation-mode-hook 'my-compilation-mode-hook))

tmk with CVS

Ignoreing tmk related files.

Q: tmk's $ARCH directory bothers me when I use cvs.

A: You can use .cvsignore file. A .cvsignore file tells to cvs which file should be ignored. If you want to ignore the Debian3.0/ directory, the .cvsignore file may be:

  % cat .cvsignore
  Debian*
There are mainly two possible locations to put this file.


tmk with Java

Under construction (I already have written an ad hoc tmk module for Java.)

Links


Copyright (C) 2000-2012 YAMAUCHI Hitoshi
Most recent update : :