深入理解使用特定案例如何解释makefile

时间:2016-06-07 16:06:54

标签: makefile

我试图深入了解makefile的工作原理。

例如,我有以下一个:

CC = gcc
CFLAGS = -I.
DEPS = int_array.h
OBJS = int_array.o test_int_array.o

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)


test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)


clean:
    rm -rf *.o test_int_array *.dSYM

我真正完全不了解的部分是:

...

%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)


test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)

...

我知道选项-c基本上只表示运行预处理器,编译和汇编步骤(即我猜不会生成可执行文件)。

-o表示将输出写入指定的文件。在这种情况下哪个文件?

我知道$@(以及$^代表权利)显然是指&#34;左&#34;一边,但哪一个?在第一种情况下,它是指:的左侧,即%.o吗?

$<是什么意思?

您能否逐步解释制作工具如何解释这两个陈述?

我想我或多或少地理解了这一部分:

...
test_int_array: $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS)

...

这应该意味着产生一个名为&#34; test_int_array&#34;的可执行文件。 (基本上由右侧-o $@文件中的这些选项$(OBJS)表示(使用选项$^声明)。

两种情况都需要$(CFLAGS)吗?订单是否重要?

2 个答案:

答案 0 :(得分:3)

在示例中:

$@

test_int_array是此规则的目标文件名:$^

OBJS是所有先决条件的名称 这将是int_array.o test_int_array.o中包含的内容,因此:%.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS)

在示例中:

$<

%.c是第一个先决条件的名称:$@

%.o是此规则的目标文件名:-I

链接不需要

$(CFLAGS),因为它只包含标志(function($) { "use strict"; /** * Plugin Constructor. Every menu must have a unique id which will either * be the actual id attribute or its index in the page. * * @param {Element} el * @param {Object} options * @param {Integer} idx * @returns {Object} Plugin Instance */ var Plugin = function(el, options, idx) { this.el = el; this.$el = $(el); this.options = options; this.uuid = this.$el.attr('id') ? this.$el.attr('id') : idx; this.state = {}; this.init(); return this; }; /** * Plugin methods */ Plugin.prototype = { /** * Load cookie, assign a unique data-index attribute to * all sub-menus and show|hide them according to cookie * or based on the parent open class. Find all parent li > a * links add the carent if it's on and attach the event click * to them. */ init: function() { var self = this; self._load(); self.$el.find('ul').each(function(idx) { var sub = $(this); sub.attr('data-index', idx); if (self.options.save && self.state.hasOwnProperty(idx)) { sub.parent().addClass(self.options.openClass); sub.show(); } else if (sub.parent().hasClass(self.options.openClass)) { sub.show(); self.state[idx] = 1; } else { sub.hide(); } }); var caret = $('<span></span>').prepend(self.options.caretHtml); var links = self.$el.find("li > a"); self._trigger(caret, false); self._trigger(links, true); self.$el.find("li:has(ul) > a").prepend(caret); }, /** * Add the main event trigger to toggle menu items to the given sources * @param {Element} sources * @param {Boolean} isLink */ _trigger: function(sources, isLink) { var self = this; sources.on('click', function(event) { event.stopPropagation(); var sub = isLink ? $(this).next() : $(this).parent().next(); var isAnchor = false; if (isLink) { var href = $(this).attr('href'); isAnchor = href === undefined || href === '' || href === '#'; } sub = sub.length > 0 ? sub : false; self.options.onClickBefore.call(this, event, sub); if (!isLink || sub && isAnchor) { event.preventDefault(); self._toggle(sub, sub.is(":hidden")); self._save(); } else if (self.options.accordion) { var allowed = self.state = self._parents($(this)); self.$el.find('ul').filter(':visible').each(function() { var sub = $(this), idx = sub.attr('data-index'); if (!allowed.hasOwnProperty(idx)) { self._toggle(sub, false); } }); self._save(); } self.options.onClickAfter.call(this, event, sub); }); }, /** * Accepts a JQuery Element and a boolean flag. If flag is false it removes the `open` css * class from the parent li and slides up the sub-menu. If flag is open it adds the `open` * css class to the parent li and slides down the menu. If accordion mode is on all * sub-menus except the direct parent tree will close. Internally an object with the menus * states is maintained for later save duty. * * @param {Element} sub * @param {Boolean} open */ _toggle: function(sub, open) { var self = this, idx = sub.attr('data-index'), parent = sub.parent(); self.options.onToggleBefore.call(this, sub, open); if (open) { parent.addClass(self.options.openClass); sub.slideDown(self.options.slide); self.state[idx] = 1; if (self.options.accordion) { var allowed = self.state = self._parents(sub); allowed[idx] = self.state[idx] = 1; self.$el.find('ul').filter(':visible').each(function() { var sub = $(this), idx = sub.attr('data-index'); if (!allowed.hasOwnProperty(idx)) { self._toggle(sub, false); } }); } } else { parent.removeClass(self.options.openClass); sub.slideUp(self.options.slide); self.state[idx] = 0; } self.options.onToggleAfter.call(this, sub, open); }, /** * Returns all parents of a sub-menu. When obj is true It returns an object with indexes for * keys and the elements as values, if obj is false the object is filled with the value `1`. * * @since v0.1.2 * @param {Element} sub * @param {Boolean} obj * @returns {Object} */ _parents: function(sub, obj) { var result = {}, parent = sub.parent(), parents = parent.parents('ul'); parents.each(function() { var par = $(this), idx = par.attr('data-index'); if (!idx) { return false; } result[idx] = obj ? par : 1; }); return result; }, /** * If `save` option is on the internal object that keeps track of the sub-menus states is * saved with a cookie. For size reasons only the open sub-menus indexes are stored. * */ _save: function() { if (this.options.save) { var save = {}; for (var key in this.state) { if (this.state[key] === 1) { save[key] = 1; } } cookie[this.uuid] = this.state = save; $.cookie(this.options.cookie.name, JSON.stringify(cookie), this.options.cookie); } }, /** * If `save` option is on it reads the cookie data. The cookie contains data for all * navgoco menus so the read happens only once and stored in the global `cookie` var. */ _load: function() { if (this.options.save) { if (cookie === null) { var data = $.cookie(this.options.cookie.name); cookie = (data) ? JSON.parse(data) : {}; } this.state = cookie.hasOwnProperty(this.uuid) ? cookie[this.uuid] : {}; } }, /** * Public method toggle to manually show|hide sub-menus. If no indexes are provided all * items will be toggled. You can pass sub-menus indexes as regular params. eg: * navgoco('toggle', true, 1, 2, 3, 4, 5); * * Since v0.1.2 it will also open parents when providing sub-menu indexes. * * @param {Boolean} open */ toggle: function(open) { var self = this, length = arguments.length; if (length <= 1) { self.$el.find('ul').each(function() { var sub = $(this); self._toggle(sub, open); }); } else { var idx, list = {}, args = Array.prototype.slice.call(arguments, 1); length--; for (var i = 0; i < length; i++) { idx = args[i]; var sub = self.$el.find('ul[data-index="' + idx + '"]').first(); if (sub) { list[idx] = sub; if (open) { var parents = self._parents(sub, true); for (var pIdx in parents) { if (!list.hasOwnProperty(pIdx)) { list[pIdx] = parents[pIdx]; } } } } } for (idx in list) { self._toggle(list[idx], open); } } self._save(); }, /** * Removes instance from JQuery data cache and unbinds events. */ destroy: function() { $.removeData(this.$el); this.$el.find("li:has(ul) > a").unbind('click'); this.$el.find("li:has(ul) > a > span").unbind('click'); } }; /** * A JQuery plugin wrapper for navgoco. It prevents from multiple instances and also handles * public methods calls. If we attempt to call a public method on an element that doesn't have * a navgoco instance, one will be created for it with the default options. * * @param {Object|String} options */ $.fn.navgoco = function(options) { if (typeof options === 'string' && options.charAt(0) !== '_' && options !== 'init') { var callback = true, args = Array.prototype.slice.call(arguments, 1); } else { options = $.extend({}, $.fn.navgoco.defaults, options || {}); if (!$.cookie) { options.save = false; } } return this.each(function(idx) { var $this = $(this), obj = $this.data('navgoco'); if (!obj) { obj = new Plugin(this, callback ? $.fn.navgoco.defaults : options, idx); $this.data('navgoco', obj); } if (callback) { obj[options].apply(obj, args); } }); }; /** * Global var holding all navgoco menus open states * * @type {Object} */ var cookie = null; /** * Default navgoco options * * @type {Object} */ $.fn.navgoco.defaults = { caretHtml: '', accordion: false, openClass: 'open', save: true, cookie: { name: 'navgoco', expires: false, path: '/' }, slide: { duration: 400, easing: 'swing' }, onClickBefore: $.noop, onClickAfter: $.noop, onToggleBefore: $.noop, onToggleAfter: $.noop }; $(document).ready(function() { $('.nav').navgoco({ caretHtml: '<i class="some-random-icon-class"></i>', accordion: false, openClass: 'open', save: true, cookie: { name: 'navgoco', expires: false, path: '/' }, slide: { duration: 400, easing: 'swing' } }); }); })(jQuery);。此外,CFLAGS表示这些标志仅用于编译,因此C FLAGS

答案 1 :(得分:2)

在Makefile中,每条规则都遵循以下格式:

resulting_file : source_files
  steps to get resulting_file from source_files

规则中分别称为左手和右手的是resul_file和source_files。

%.ext : %.ext2

是一种模式规则。它允许Makefile自动创建所需的任何.ext文件,如果它可以使用.ext2在同一路径中找到文件。

%.c : %.o

是从等效的.o文件中获取.c文件(int_array.o test_int_array.o)的模式规则(int_array.c test_int_array.c)

当您指定构建$(OBJS)文件需要test_int_array时,会调用此方法。

模式规则会自动使用某些变量,例如$(CFLAGS),因此您无需在该规则中手动添加它。您可以在此处找到模式规则中隐式使用的变量的完整列表:https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC96

您可以在此处了解$@$<$^及类似内容:https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_10.html#SEC101

$@:整个左手

$<:右手中的第一个文件

$^:整个文件右侧列表,空格分隔。