我试图深入了解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)
吗?订单是否重要?
答案 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
$@
:整个左手
$<
:右手中的第一个文件
$^
:整个文件右侧列表,空格分隔。